(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define('simditor', ["jquery",
          "simple-module",
          "simple-hotkeys",
          "simple-uploader"],
        function ($, SimpleModule, simpleHotkeys, simpleUploader) {
          return (root.returnExportsGlobal = factory($, SimpleModule,
              simpleHotkeys, simpleUploader));
        });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like enviroments that support module.exports,
    // like Node.
    module.exports = factory(require("jquery"),
        require("simple-module"),
        require("simple-hotkeys"),
        require("simple-uploader"));
  } else {
    root['Simditor'] = factory(jQuery,
        SimpleModule,
        simple.hotkeys,
        simple.uploader);
  }
}(this, function ($, SimpleModule, simpleHotkeys, simpleUploader) {

  var Selection,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Selection = (function (_super) {
    __extends(Selection, _super);

    function Selection() {
      return Selection.__super__.constructor.apply(this, arguments);
    }

    Selection.pluginName = 'Selection';

    Selection.prototype._init = function () {
      this.editor = this._module;
      return this.sel = document.getSelection();
    };

    Selection.prototype.clear = function () {
      var e;
      try {
        return this.sel.removeAllRanges();
      } catch (_error) {
        e = _error;
      }
    };

    Selection.prototype.getRange = function () {
      if (!this.editor.inputManager.focused || !this.sel.rangeCount) {
        return null;
      }
      return this.sel.getRangeAt(0);
    };

    Selection.prototype.selectRange = function (range) {
      this.clear();
      this.sel.addRange(range);
      if (!this.editor.inputManager.focused && (this.editor.util.browser.firefox
          || this.editor.util.browser.msie)) {
        this.editor.body.focus();
      }
      return range;
    };

    Selection.prototype.rangeAtEndOf = function (node, range) {
      var endNode, endNodeLength, result;
      if (range == null) {
        range = this.getRange();
      }
      if (!((range != null) && range.collapsed)) {
        return;
      }
      node = $(node)[0];
      endNode = range.endContainer;
      endNodeLength = this.editor.util.getNodeLength(endNode);
      if (!(range.endOffset === endNodeLength - 1 && $(
          endNode).contents().last().is('br')) && range.endOffset
          !== endNodeLength) {
        return false;
      }
      if (node === endNode) {
        return true;
      } else if (!$.contains(node, endNode)) {
        return false;
      }
      result = true;
      $(endNode).parentsUntil(node).addBack().each((function (_this) {
        return function (i, n) {
          var $lastChild, nodes;
          nodes = $(n).parent().contents().filter(function () {
            return !(this !== n && this.nodeType === 3 && !this.nodeValue);
          });
          $lastChild = nodes.last();
          if (!($lastChild.get(0) === n || ($lastChild.is('br')
              && $lastChild.prev().get(0) === n))) {
            result = false;
            return false;
          }
        };
      })(this));
      return result;
    };

    Selection.prototype.rangeAtStartOf = function (node, range) {
      var result, startNode;
      if (range == null) {
        range = this.getRange();
      }
      if (!((range != null) && range.collapsed)) {
        return;
      }
      node = $(node)[0];
      startNode = range.startContainer;
      if (range.startOffset !== 0) {
        return false;
      }
      if (node === startNode) {
        return true;
      } else if (!$.contains(node, startNode)) {
        return false;
      }
      result = true;
      $(startNode).parentsUntil(node).addBack().each((function (_this) {
        return function (i, n) {
          var nodes;
          nodes = $(n).parent().contents().filter(function () {
            return !(this !== n && this.nodeType === 3 && !this.nodeValue);
          });
          if (nodes.first().get(0) !== n) {
            return result = false;
          }
        };
      })(this));
      return result;
    };

    Selection.prototype.insertNode = function (node, range) {
      if (range == null) {
        range = this.getRange();
      }
      if (range == null) {
        return;
      }
      node = $(node)[0];
      range.insertNode(node);
      return this.setRangeAfter(node, range);
    };

    Selection.prototype.setRangeAfter = function (node, range) {
      if (range == null) {
        range = this.getRange();
      }
      if (range == null) {
        return;
      }
      node = $(node)[0];
      range.setEndAfter(node);
      range.collapse(false);
      return this.selectRange(range);
    };

    Selection.prototype.setRangeBefore = function (node, range) {
      if (range == null) {
        range = this.getRange();
      }
      if (range == null) {
        return;
      }
      node = $(node)[0];
      range.setEndBefore(node);
      range.collapse(false);
      return this.selectRange(range);
    };

    Selection.prototype.setRangeAtStartOf = function (node, range) {
      if (range == null) {
        range = this.getRange();
      }
      node = $(node).get(0);
      range.setEnd(node, 0);
      range.collapse(false);
      return this.selectRange(range);
    };

    Selection.prototype.setRangeAtEndOf = function (node, range) {
      var $lastNode, $node, contents, lastChild, lastText, nodeLength;
      if (range == null) {
        range = this.getRange();
      }
      $node = $(node);
      node = $node.get(0);
      if ($node.is('pre')) {
        contents = $node.contents();
        if (contents.length > 0) {
          lastChild = contents.last();
          lastText = lastChild.text();
          if (lastText.charAt(lastText.length - 1) === '\n') {
            range.setEnd(lastChild[0],
                this.editor.util.getNodeLength(lastChild[0]) - 1);
          } else {
            range.setEnd(lastChild[0],
                this.editor.util.getNodeLength(lastChild[0]));
          }
        } else {
          range.setEnd(node, 0);
        }
      } else {
        nodeLength = this.editor.util.getNodeLength(node);
        if (node.nodeType !== 3 && nodeLength > 0) {
          $lastNode = $(node).contents().last();
          if ($lastNode.is('br')) {
            nodeLength -= 1;
          } else if ($lastNode[0].nodeType !== 3
              && this.editor.util.isEmptyNode($lastNode)) {
            $lastNode.append(this.editor.util.phBr);
            node = $lastNode[0];
            nodeLength = 0;
          }
        }
        range.setEnd(node, nodeLength);
      }
      range.collapse(false);
      return this.selectRange(range);
    };

    Selection.prototype.deleteRangeContents = function (range) {
      var endRange, startRange;
      if (range == null) {
        range = this.getRange();
      }
      startRange = range.cloneRange();
      endRange = range.cloneRange();
      startRange.collapse(true);
      endRange.collapse(false);
      if (!range.collapsed && this.rangeAtStartOf(this.editor.body, startRange)
          && this.rangeAtEndOf(this.editor.body, endRange)) {
        this.editor.body.empty();
        range.setStart(this.editor.body[0], 0);
        range.collapse(true);
        this.selectRange(range);
      } else {
        range.deleteContents();
      }
      return range;
    };

    Selection.prototype.breakBlockEl = function (el, range) {
      var $el;
      if (range == null) {
        range = this.getRange();
      }
      $el = $(el);
      if (!range.collapsed) {
        return $el;
      }
      range.setStartBefore($el.get(0));
      if (range.collapsed) {
        return $el;
      }
      return $el.before(range.extractContents());
    };

    Selection.prototype.save = function (range) {
      var endCaret, endRange, startCaret;
      if (range == null) {
        range = this.getRange();
      }
      if (this._selectionSaved) {
        return;
      }
      endRange = range.cloneRange();
      endRange.collapse(false);
      startCaret = $('<span/>').addClass('simditor-caret-start');
      endCaret = $('<span/>').addClass('simditor-caret-end');
      endRange.insertNode(endCaret[0]);
      range.insertNode(startCaret[0]);
      this.clear();
      return this._selectionSaved = true;
    };

    Selection.prototype.restore = function () {
      var endCaret, endContainer, endOffset, range, startCaret, startContainer,
          startOffset;
      if (!this._selectionSaved) {
        return false;
      }
      startCaret = this.editor.body.find('.simditor-caret-start');
      endCaret = this.editor.body.find('.simditor-caret-end');
      if (startCaret.length && endCaret.length) {
        startContainer = startCaret.parent();
        startOffset = startContainer.contents().index(startCaret);
        endContainer = endCaret.parent();
        endOffset = endContainer.contents().index(endCaret);
        if (startContainer[0] === endContainer[0]) {
          endOffset -= 1;
        }
        range = document.createRange();
        range.setStart(startContainer.get(0), startOffset);
        range.setEnd(endContainer.get(0), endOffset);
        startCaret.remove();
        endCaret.remove();
        this.selectRange(range);
      } else {
        startCaret.remove();
        endCaret.remove();
      }
      this._selectionSaved = false;
      return range;
    };

    return Selection;

  })(SimpleModule);

  var Formatter,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __indexOf = [].indexOf || function (item) {
        for (var i = 0, l = this.length; i < l; i++) {
          if (i in this && this[i] === item) {
            return i;
          }
        }
        return -1;
      };

  Formatter = (function (_super) {
    __extends(Formatter, _super);

    function Formatter() {
      return Formatter.__super__.constructor.apply(this, arguments);
    }

    Formatter.pluginName = 'Formatter';

    Formatter.prototype._init = function () {
      this.editor = this._module;
      this._allowedTags = ['br', 'a', 'img', 'b', 'strong', 'i', 'u', 'font',
        'p', 'ul', 'ol', 'li', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4',
        'hr'];
      this._allowedAttributes = {
        img: ['src', 'alt', 'width', 'height', 'data-image-src',
          'data-image-size', 'data-image-name', 'data-non-image'],
        a: ['href', 'target'],
        font: ['color'],
        pre: ['data-lang', 'class'],
        p: ['data-indent'],
        h1: ['data-indent'],
        h2: ['data-indent'],
        h3: ['data-indent'],
        h4: ['data-indent']
      };
      return this.editor.body.on('click', 'a', (function (_this) {
        return function (e) {
          return false;
        };
      })(this));
    };

    Formatter.prototype.decorate = function ($el) {
      if ($el == null) {
        $el = this.editor.body;
      }
      return this.editor.trigger('decorate', [$el]);
    };

    Formatter.prototype.undecorate = function ($el) {
      if ($el == null) {
        $el = this.editor.body.clone();
      }
      this.editor.trigger('undecorate', [$el]);
      return $.trim($el.html());
    };

    Formatter.prototype.autolink = function ($el) {
      var $node, findLinkNode, lastIndex, linkNodes, match, re, replaceEls,
          text, uri, _i, _len;
      if ($el == null) {
        $el = this.editor.body;
      }
      linkNodes = [];
      findLinkNode = function ($parentNode) {
        return $parentNode.contents().each(function (i, node) {
          var $node, text;
          $node = $(node);
          if ($node.is('a') || $node.closest('a, pre', $el).length) {
            return;
          }
          if ($node.contents().length) {
            return findLinkNode($node);
          } else if ((text = $node.text()) && /https?:\/\/|www\./ig.test(
              text)) {
            return linkNodes.push($node);
          }
        });
      };
      findLinkNode($el);
      re = /(https?:\/\/|www\.)[\w\-\.\?&=\/#%:,@\!\+]+/ig;
      for (_i = 0, _len = linkNodes.length; _i < _len; _i++) {
        $node = linkNodes[_i];
        text = $node.text();
        replaceEls = [];
        match = null;
        lastIndex = 0;
        while ((match = re.exec(text)) !== null) {
          replaceEls.push(
              document.createTextNode(text.substring(lastIndex, match.index)));
          lastIndex = re.lastIndex;
          uri = /^(http(s)?:\/\/|\/)/.test(match[0]) ? match[0] : 'http://'
              + match[0];
          replaceEls.push(
              $('<a href="' + uri + '" rel="nofollow"></a>').text(match[0])[0]);
        }
        replaceEls.push(document.createTextNode(text.substring(lastIndex)));
        $node.replaceWith($(replaceEls));
      }
      return $el;
    };

    Formatter.prototype.format = function ($el) {
      var $node, blockNode, n, node, _i, _j, _len, _len1, _ref, _ref1;
      if ($el == null) {
        $el = this.editor.body;
      }
      if ($el.is(':empty')) {
        $el.append('<p>' + this.editor.util.phBr + '</p>');
        return $el;
      }
      _ref = $el.contents();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        n = _ref[_i];
        this.cleanNode(n, true);
      }
      _ref1 = $el.contents();
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        node = _ref1[_j];
        $node = $(node);
        if ($node.is('br')) {
          if (typeof blockNode !== "undefined" && blockNode !== null) {
            blockNode = null;
          }
          $node.remove();
        } else if (this.editor.util.isBlockNode(node)) {
          if ($node.is('li')) {
            if (blockNode && blockNode.is('ul, ol')) {
              blockNode.append(node);
            } else {
              blockNode = $('<ul/>').insertBefore(node);
              blockNode.append(node);
            }
          } else {
            blockNode = null;
          }
        } else {
          if (!blockNode || blockNode.is('ul, ol')) {
            blockNode = $('<p/>').insertBefore(node);
          }
          blockNode.append(node);
        }
      }
      return $el;
    };

    Formatter.prototype.cleanNode = function (node, recursive) {
      var $childImg, $node, $p, $td, allowedAttributes, attr, contents,
          isDecoration, n, text, textNode, _i, _j, _len, _len1, _ref, _ref1;
      $node = $(node);
      if (!($node.length > 0)) {
        return;
      }
      if ($node[0].nodeType === 3) {
        text = $node.text().replace(/(\r\n|\n|\r)/gm, '');
        if (text) {
          textNode = document.createTextNode(text);
          $node.replaceWith(textNode);
        } else {
          $node.remove();
        }
        return;
      }
      contents = $node.contents();
      isDecoration = $node.is('[class^="simditor-"]');
      if ($node.is(this._allowedTags.join(',')) || isDecoration) {
        if ($node.is('a') && ($childImg = $node.find('img')).length > 0) {
          $node.replaceWith($childImg);
          $node = $childImg;
          contents = null;
        }
        if ($node.is('img') && $node.hasClass('uploading')) {
          $node.remove();
        }
        if (!isDecoration) {
          allowedAttributes = this._allowedAttributes[$node[0].tagName.toLowerCase()];
          _ref = $.makeArray($node[0].attributes);
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            attr = _ref[_i];
            if (!((allowedAttributes != null)
                && (_ref1 = attr.name, __indexOf.call(allowedAttributes, _ref1)
                >= 0))) {
              $node.removeAttr(attr.name);
            }
          }
        }
      } else if ($node[0].nodeType === 1 && !$node.is(':empty')) {
        if ($node.is('div, article, dl, header, footer, tr')) {
          $node.append('<br/>');
          contents.first().unwrap();
        } else if ($node.is('table')) {
          $p = $('<p/>');
          $node.find('tr').each((function (_this) {
            return function (i, tr) {
              return $p.append($(tr).text() + '<br/>');
            };
          })(this));
          $node.replaceWith($p);
          contents = null;
        } else if ($node.is('thead, tfoot')) {
          $node.remove();
          contents = null;
        } else if ($node.is('th')) {
          $td = $('<td/>').append($node.contents());
          $node.replaceWith($td);
        } else {
          contents.first().unwrap();
        }
      } else {
        $node.remove();
        contents = null;
      }
      if (recursive && (contents != null) && !$node.is('pre')) {
        for (_j = 0, _len1 = contents.length; _j < _len1; _j++) {
          n = contents[_j];
          this.cleanNode(n, true);
        }
      }
      return null;
    };

    Formatter.prototype.clearHtml = function (html, lineBreak) {
      var container, contents, result;
      if (lineBreak == null) {
        lineBreak = true;
      }
      container = $('<div/>').append(html);
      contents = container.contents();
      result = '';
      contents.each((function (_this) {
        return function (i, node) {
          var $node, children;
          if (node.nodeType === 3) {
            return result += node.nodeValue;
          } else if (node.nodeType === 1) {
            $node = $(node);
            children = $node.contents();
            if (children.length > 0) {
              result += _this.clearHtml(children);
            }
            if (lineBreak && i < contents.length - 1 && $node.is(
                'br, p, div, li, tr, pre, address, artticle, aside, dl, figcaption, footer, h1, h2, h3, h4, header')) {
              return result += '\n';
            }
          }
        };
      })(this));
      return result;
    };

    Formatter.prototype.beautify = function ($contents) {
      var uselessP;
      uselessP = function ($el) {
        return !!($el.is('p') && !$el.text() && $el.children(':not(br)').length
            < 1);
      };
      return $contents.each((function (_this) {
        return function (i, el) {
          var $el;
          $el = $(el);
          if ($el.is(
              ':not(img, br, col, td, hr, [class^="simditor-"]):empty')) {
            $el.remove();
          }
          if (uselessP($el)) {
            $el.remove();
          }
          return $el.find(
              ':not(img, br, col, td, hr, [class^="simditor-"]):empty').remove();
        };
      })(this));
    };

    return Formatter;

  })(SimpleModule);

  var InputManager,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __indexOf = [].indexOf || function (item) {
        for (var i = 0, l = this.length; i < l; i++) {
          if (i in this && this[i] === item) {
            return i;
          }
        }
        return -1;
      };

  InputManager = (function (_super) {
    __extends(InputManager, _super);

    function InputManager() {
      return InputManager.__super__.constructor.apply(this, arguments);
    }

    InputManager.pluginName = 'InputManager';

    InputManager.prototype.opts = {
      pasteImage: false
    };

    InputManager.prototype._modifierKeys = [16, 17, 18, 91, 93, 224];

    InputManager.prototype._arrowKeys = [37, 38, 39, 40];

    InputManager.prototype._init = function () {
      var submitKey;
      this.editor = this._module;
      if (this.opts.pasteImage && typeof this.opts.pasteImage !== 'string') {
        this.opts.pasteImage = 'inline';
      }
      this._keystrokeHandlers = {};
      this.hotkeys = simpleHotkeys({
        el: this.editor.body
      });
      this._pasteArea = $('<div/>').css({
        width: '1px',
        height: '1px',
        overflow: 'hidden',
        position: 'fixed',
        right: '0',
        bottom: '100px'
      }).attr({
        tabIndex: '-1',
        contentEditable: true
      }).addClass('simditor-paste-area').appendTo(this.editor.el);
      this._cleanPasteArea = $('<textarea/>').css({
        width: '1px',
        height: '1px',
        overflow: 'hidden',
        position: 'fixed',
        right: '0',
        bottom: '101px'
      }).attr({
        tabIndex: '-1'
      }).addClass('simditor-clean-paste-area').appendTo(this.editor.el);
      $(document).on('selectionchange.simditor' + this.editor.id,
          (function (_this) {
            return function (e) {
              if (!_this.focused) {
                return;
              }
              if (_this._selectionTimer) {
                clearTimeout(_this._selectionTimer);
                _this._selectionTimer = null;
              }
              return _this._selectionTimer = setTimeout(function () {
                return _this.editor.trigger('selectionchanged');
              }, 20);
            };
          })(this));
      this.editor.on('valuechanged', (function (_this) {
        return function () {
          if (!_this.editor.util.closestBlockEl() && _this.focused) {
            _this.editor.selection.save();
            _this.editor.formatter.format();
            _this.editor.selection.restore();
          }
          _this.editor.body.find('hr, pre, .simditor-table').each(
              function (i, el) {
                var $el, formatted;
                $el = $(el);
                if ($el.parent().is('blockquote') || $el.parent()[0]
                    === _this.editor.body[0]) {
                  formatted = false;
                  if ($el.next().length === 0) {
                    $('<p/>').append(_this.editor.util.phBr).insertAfter($el);
                    formatted = true;
                  }
                  if ($el.prev().length === 0) {
                    $('<p/>').append(_this.editor.util.phBr).insertBefore($el);
                    formatted = true;
                  }
                  if (formatted) {
                    return setTimeout(function () {
                      return _this.editor.trigger('valuechanged');
                    }, 10);
                  }
                }
              });
          _this.editor.body.find('pre:empty').append(_this.editor.util.phBr);
          if (!_this.editor.util.supportSelectionChange && _this.focused) {
            return _this.editor.trigger('selectionchanged');
          }
        };
      })(this));
      this.editor.on('selectionchanged', (function (_this) {
        return function (e) {
          return _this.editor.undoManager.update();
        };
      })(this));
      this.editor.body.on('keydown', $.proxy(this._onKeyDown, this)).on(
          'keypress', $.proxy(this._onKeyPress, this)).on('keyup',
          $.proxy(this._onKeyUp, this)).on('mouseup',
          $.proxy(this._onMouseUp, this)).on('focus',
          $.proxy(this._onFocus, this)).on('blur',
          $.proxy(this._onBlur, this)).on('paste',
          $.proxy(this._onPaste, this)).on('drop', $.proxy(this._onDrop, this));
      if (this.editor.util.browser.firefox) {
        this.addShortcut('cmd+left', (function (_this) {
          return function (e) {
            e.preventDefault();
            _this.editor.selection.sel.modify('move', 'backward',
                'lineboundary');
            return false;
          };
        })(this));
        this.addShortcut('cmd+right', (function (_this) {
          return function (e) {
            e.preventDefault();
            _this.editor.selection.sel.modify('move', 'forward',
                'lineboundary');
            return false;
          };
        })(this));
        this.addShortcut('cmd+a', (function (_this) {
          return function (e) {
            var $children, firstBlock, lastBlock, range;
            $children = _this.editor.body.children();
            if (!($children.length > 0)) {
              return;
            }
            firstBlock = $children.first().get(0);
            lastBlock = $children.last().get(0);
            range = document.createRange();
            range.setStart(firstBlock, 0);
            range.setEnd(lastBlock, _this.editor.util.getNodeLength(lastBlock));
            _this.editor.selection.selectRange(range);
            return false;
          };
        })(this));
      }
      submitKey = this.editor.util.os.mac ? 'cmd+enter' : 'ctrl+enter';
      this.addShortcut(submitKey, (function (_this) {
        return function (e) {
          _this.editor.el.closest('form').find('button:submit').click();
          return false;
        };
      })(this));
      if (this.editor.textarea.attr('autofocus')) {
        return setTimeout((function (_this) {
          return function () {
            return _this.editor.focus();
          };
        })(this), 0);
      }
    };

    InputManager.prototype._onFocus = function (e) {
      this.editor.el.addClass('focus').removeClass('error');
      this.focused = true;
      this.lastCaretPosition = null;
      return setTimeout((function (_this) {
        return function () {
          _this.editor.triggerHandler('focus');
          return _this.editor.trigger('selectionchanged');
        };
      })(this), 0);
    };

    InputManager.prototype._onBlur = function (e) {
      var _ref;
      this.editor.el.removeClass('focus');
      this.editor.sync();
      this.focused = false;
      this.lastCaretPosition = (_ref = this.editor.undoManager.currentState())
      != null ? _ref.caret : void 0;
      return this.editor.triggerHandler('blur');
    };

    InputManager.prototype._onMouseUp = function (e) {
      if (!this.editor.util.supportSelectionChange) {
        return setTimeout((function (_this) {
          return function () {
            return _this.editor.trigger('selectionchanged');
          };
        })(this), 0);
      }
    };

    InputManager.prototype._onKeyDown = function (e) {
      var $blockEl, metaKey, result, _base, _ref, _ref1;
      if (this.editor.triggerHandler(e) === false) {
        return false;
      }
      if (this.hotkeys.respondTo(e)) {
        return;
      }
      if (e.which in this._keystrokeHandlers) {
        result = typeof (_base = this._keystrokeHandlers[e.which])['*']
        === "function" ? _base['*'](e) : void 0;
        if (result) {
          this.editor.trigger('valuechanged');
          return false;
        }
        this.editor.util.traverseUp((function (_this) {
          return function (node) {
            var handler, _ref;
            if (node.nodeType !== 1) {
              return;
            }
            handler = (_ref = _this._keystrokeHandlers[e.which]) != null
                ? _ref[node.tagName.toLowerCase()] : void 0;
            result = typeof handler === "function" ? handler(e, $(node))
                : void 0;
            if (result === true || result === false) {
              return false;
            }
          };
        })(this));
        if (result) {
          this.editor.trigger('valuechanged');
          return false;
        }
      }
      if ((_ref = e.which, __indexOf.call(this._modifierKeys, _ref) >= 0)
          || (_ref1 = e.which, __indexOf.call(this._arrowKeys, _ref1) >= 0)) {
        return;
      }
      metaKey = this.editor.util.metaKey(e);
      $blockEl = this.editor.util.closestBlockEl();
      if (metaKey && e.which === 86) {
        return;
      }
      if (this.editor.util.browser.webkit && e.which === 8
          && this.editor.selection.rangeAtStartOf($blockEl)) {
        setTimeout((function (_this) {
          return function () {
            var $newBlockEl;
            if (!_this.focused) {
              return;
            }
            $newBlockEl = _this.editor.util.closestBlockEl();
            _this.editor.selection.save();
            _this.editor.formatter.cleanNode($newBlockEl, true);
            _this.editor.selection.restore();
            return _this.editor.trigger('valuechanged');
          };
        })(this), 10);
        this.typing = true;
      } else if (this._typing) {
        if (this._typing !== true) {
          clearTimeout(this._typing);
        }
        this._typing = setTimeout((function (_this) {
          return function () {
            _this.editor.trigger('valuechanged');
            return _this._typing = false;
          };
        })(this), 200);
      } else {
        setTimeout((function (_this) {
          return function () {
            return _this.editor.trigger('valuechanged');
          };
        })(this), 10);
        this._typing = true;
      }
      return null;
    };

    InputManager.prototype._onKeyPress = function (e) {
      if (this.editor.triggerHandler(e) === false) {
        return false;
      }
    };

    InputManager.prototype._onKeyUp = function (e) {
      var p, _ref;
      if (this.editor.triggerHandler(e) === false) {
        return false;
      }
      if (!this.editor.util.supportSelectionChange
          && (_ref = e.which, __indexOf.call(this._arrowKeys, _ref) >= 0)) {
        this.editor.trigger('selectionchanged');
        return;
      }
      if ((e.which === 8 || e.which === 46) && this.editor.util.isEmptyNode(
          this.editor.body)) {
        this.editor.body.empty();
        p = $('<p/>').append(this.editor.util.phBr).appendTo(this.editor.body);
        this.editor.selection.setRangeAtStartOf(p);
      }
    };

    InputManager.prototype._onPaste = function (e) {
      var $blockEl, cleanPaste, imageFile, pasteItem, range, uploadOpt, _ref;
      if (this.editor.triggerHandler(e) === false) {
        return false;
      }
      range = this.editor.selection.deleteRangeContents();
      if (!range.collapsed) {
        range.collapse(true);
      }
      $blockEl = this.editor.util.closestBlockEl();
      cleanPaste = $blockEl.is('pre, table');
      if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.items
          && e.originalEvent.clipboardData.items.length > 0) {
        pasteItem = e.originalEvent.clipboardData.items[0];
        if (/^image\//.test(pasteItem.type) && !cleanPaste) {
          imageFile = pasteItem.getAsFile();
          if (!((imageFile != null) && this.opts.pasteImage)) {
            return;
          }
          if (!imageFile.name) {
            imageFile.name = "Clipboard Image.png";
          }
          uploadOpt = {};
          uploadOpt[this.opts.pasteImage] = true;
          if ((_ref = this.editor.uploader) != null) {
            _ref.upload(imageFile, uploadOpt);
          }
          return false;
        }
      }
      this.editor.selection.save(range);
      if (cleanPaste) {
        this._cleanPasteArea.focus();
        if (this.editor.util.browser.firefox) {
          e.preventDefault();
          this._cleanPasteArea.val(
              e.originalEvent.clipboardData.getData('text/plain'));
        } else if (this.editor.util.browser.msie
            && this.editor.util.browser.version === 10) {
          e.preventDefault();
          this._cleanPasteArea.val(window.clipboardData.getData('Text'));
        }
      } else {
        this._pasteArea.focus();
        if (this.editor.util.browser.msie && this.editor.util.browser.version
            === 10) {
          e.preventDefault();
          this._pasteArea.html(window.clipboardData.getData('Text'));
        }
      }
      return setTimeout((function (_this) {
        return function () {
          var $img, blob, children, insertPosition, lastLine, line, lines, node,
              pasteContent, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4,
              _m, _ref1, _ref2, _ref3;
          if (_this._pasteArea.is(':empty') && !_this._cleanPasteArea.val()) {
            pasteContent = null;
          } else if (cleanPaste) {
            pasteContent = _this._cleanPasteArea.val();
          } else {
            pasteContent = $('<div/>').append(_this._pasteArea.contents());
            pasteContent.find('table colgroup').remove();
            _this.editor.formatter.format(pasteContent);
            _this.editor.formatter.decorate(pasteContent);
            _this.editor.formatter.beautify(pasteContent.children());
            pasteContent = pasteContent.contents();
          }
          _this._pasteArea.empty();
          _this._cleanPasteArea.val('');
          range = _this.editor.selection.restore();
          if (_this.editor.triggerHandler('pasting', [pasteContent])
              === false) {
            return;
          }
          if (!pasteContent) {
            return;
          } else if (cleanPaste) {
            if ($blockEl.is('table')) {
              lines = pasteContent.split('\n');
              lastLine = lines.pop();
              for (_i = 0, _len = lines.length; _i < _len; _i++) {
                line = lines[_i];
                _this.editor.selection.insertNode(
                    document.createTextNode(line));
                _this.editor.selection.insertNode($('<br/>'));
              }
              _this.editor.selection.insertNode(
                  document.createTextNode(lastLine));
            } else {
              pasteContent = $('<div/>').text(pasteContent);
              _ref1 = pasteContent.contents();
              for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
                node = _ref1[_j];
                _this.editor.selection.insertNode($(node)[0], range);
              }
            }
          } else if ($blockEl.is(_this.editor.body)) {
            for (_k = 0, _len2 = pasteContent.length; _k < _len2; _k++) {
              node = pasteContent[_k];
              _this.editor.selection.insertNode(node, range);
            }
          } else if (pasteContent.length < 1) {
            return;
          } else if (pasteContent.length === 1) {
            if (pasteContent.is('p')) {
              children = pasteContent.contents();
              if (children.length === 1 && children.is('img')) {
                $img = children;
                if (/^data:image/.test($img.attr('src'))) {
                  if (!_this.opts.pasteImage) {
                    return;
                  }
                  blob = _this.editor.util.dataURLtoBlob($img.attr("src"));
                  blob.name = "Clipboard Image.png";
                  uploadOpt = {};
                  uploadOpt[_this.opts.pasteImage] = true;
                  if ((_ref2 = _this.editor.uploader) != null) {
                    _ref2.upload(blob, uploadOpt);
                  }
                  return;
                } else if ($img.is('img[src^="webkit-fake-url://"]')) {
                  return;
                }
              }
              for (_l = 0, _len3 = children.length; _l < _len3; _l++) {
                node = children[_l];
                _this.editor.selection.insertNode(node, range);
              }
            } else if ($blockEl.is('p') && _this.editor.util.isEmptyNode(
                $blockEl)) {
              $blockEl.replaceWith(pasteContent);
              _this.editor.selection.setRangeAtEndOf(pasteContent, range);
            } else if (pasteContent.is('ul, ol')) {
              if (pasteContent.find('li').length === 1) {
                pasteContent = $('<div/>').text(pasteContent.text());
                _ref3 = pasteContent.contents();
                for (_m = 0, _len4 = _ref3.length; _m < _len4; _m++) {
                  node = _ref3[_m];
                  _this.editor.selection.insertNode($(node)[0], range);
                }
              } else if ($blockEl.is('li')) {
                $blockEl.parent().after(pasteContent);
                _this.editor.selection.setRangeAtEndOf(pasteContent, range);
              } else {
                $blockEl.after(pasteContent);
                _this.editor.selection.setRangeAtEndOf(pasteContent, range);
              }
            } else {
              $blockEl.after(pasteContent);
              _this.editor.selection.setRangeAtEndOf(pasteContent, range);
            }
          } else {
            if ($blockEl.is('li')) {
              $blockEl = $blockEl.parent();
            }
            if (_this.editor.selection.rangeAtStartOf($blockEl, range)) {
              insertPosition = 'before';
            } else if (_this.editor.selection.rangeAtEndOf($blockEl, range)) {
              insertPosition = 'after';
            } else {
              _this.editor.selection.breakBlockEl($blockEl, range);
              insertPosition = 'before';
            }
            $blockEl[insertPosition](pasteContent);
            _this.editor.selection.setRangeAtEndOf(pasteContent.last(), range);
          }
          return _this.editor.trigger('valuechanged');
        };
      })(this), 10);
    };

    InputManager.prototype._onDrop = function (e) {
      if (this.editor.triggerHandler(e) === false) {
        return false;
      }
      return setTimeout((function (_this) {
        return function () {
          return _this.editor.trigger('valuechanged');
        };
      })(this), 0);
    };

    InputManager.prototype.addKeystrokeHandler = function (key, node, handler) {
      if (!this._keystrokeHandlers[key]) {
        this._keystrokeHandlers[key] = {};
      }
      return this._keystrokeHandlers[key][node] = handler;
    };

    InputManager.prototype.addShortcut = function (keys, handler) {
      return this.hotkeys.add(keys, $.proxy(handler, this));
    };

    return InputManager;

  })(SimpleModule);

  var Keystroke,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Keystroke = (function (_super) {
    __extends(Keystroke, _super);

    function Keystroke() {
      return Keystroke.__super__.constructor.apply(this, arguments);
    }

    Keystroke.pluginName = 'Keystroke';

    Keystroke.prototype._init = function () {
      var titleEnterHandler;
      this.editor = this._module;
      if (this.editor.util.browser.safari) {
        this.editor.inputManager.addKeystrokeHandler('13', '*',
            (function (_this) {
              return function (e) {
                var $blockEl, $br;
                if (!e.shiftKey) {
                  return;
                }
                $blockEl = _this.editor.util.closestBlockEl();
                if ($blockEl.is('pre')) {
                  return;
                }
                $br = $('<br/>');
                if (_this.editor.selection.rangeAtEndOf($blockEl)) {
                  _this.editor.selection.insertNode($br);
                  _this.editor.selection.insertNode($('<br/>'));
                  _this.editor.selection.setRangeBefore($br);
                } else {
                  _this.editor.selection.insertNode($br);
                }
                return true;
              };
            })(this));
      }
      if (this.editor.util.browser.webkit || this.editor.util.browser.msie) {
        titleEnterHandler = (function (_this) {
          return function (e, $node) {
            var $p;
            if (!_this.editor.selection.rangeAtEndOf($node)) {
              return;
            }
            $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node);
            _this.editor.selection.setRangeAtStartOf($p);
            return true;
          };
        })(this);
        this.editor.inputManager.addKeystrokeHandler('13', 'h1',
            titleEnterHandler);
        this.editor.inputManager.addKeystrokeHandler('13', 'h2',
            titleEnterHandler);
        this.editor.inputManager.addKeystrokeHandler('13', 'h3',
            titleEnterHandler);
        this.editor.inputManager.addKeystrokeHandler('13', 'h4',
            titleEnterHandler);
        this.editor.inputManager.addKeystrokeHandler('13', 'h5',
            titleEnterHandler);
        this.editor.inputManager.addKeystrokeHandler('13', 'h6',
            titleEnterHandler);
      }
      this.editor.inputManager.addKeystrokeHandler('8', '*', (function (_this) {
        return function (e) {
          var $prevBlockEl, $rootBlock;
          $rootBlock = _this.editor.util.furthestBlockEl();
          $prevBlockEl = $rootBlock.prev();
          if ($prevBlockEl.is('hr') && _this.editor.selection.rangeAtStartOf(
              $rootBlock)) {
            _this.editor.selection.save();
            $prevBlockEl.remove();
            _this.editor.selection.restore();
            return true;
          }
        };
      })(this));
      this.editor.inputManager.addKeystrokeHandler('9', '*', (function (_this) {
        return function (e) {
          var codeButton;
          codeButton = _this.editor.toolbar.findButton('code');
          if (!(_this.editor.opts.tabIndent || (codeButton
              && codeButton.active))) {
            return;
          }
          if (e.shiftKey) {
            _this.editor.util.outdent();
          } else {
            _this.editor.util.indent();
          }
          return true;
        };
      })(this));
      this.editor.inputManager.addKeystrokeHandler('13', 'li',
          (function (_this) {
            return function (e, $node) {
              var $cloneNode, listEl, newBlockEl, newListEl;
              $cloneNode = $node.clone();
              $cloneNode.find('ul, ol').remove();
              if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(
                  _this.editor.util.closestBlockEl()))) {
                return;
              }
              listEl = $node.parent();
              if ($node.next('li').length > 0) {
                if (!_this.editor.util.isEmptyNode($node)) {
                  return;
                }
                if (listEl.parent('li').length > 0) {
                  newBlockEl = $('<li/>').append(
                      _this.editor.util.phBr).insertAfter(listEl.parent('li'));
                  newListEl = $('<' + listEl[0].tagName + '/>').append(
                      $node.nextAll('li'));
                  newBlockEl.append(newListEl);
                } else {
                  newBlockEl = $('<p/>').append(
                      _this.editor.util.phBr).insertAfter(listEl);
                  newListEl = $('<' + listEl[0].tagName + '/>').append(
                      $node.nextAll('li'));
                  newBlockEl.after(newListEl);
                }
              } else {
                if (listEl.parent('li').length > 0) {
                  newBlockEl = $('<li/>').insertAfter(listEl.parent('li'));
                  if ($node.contents().length > 0) {
                    newBlockEl.append($node.contents());
                  } else {
                    newBlockEl.append(_this.editor.util.phBr);
                  }
                } else {
                  newBlockEl = $('<p/>').append(
                      _this.editor.util.phBr).insertAfter(listEl);
                  if ($node.children('ul, ol').length > 0) {
                    newBlockEl.after($node.children('ul, ol'));
                  }
                }
              }
              if ($node.prev('li').length) {
                $node.remove();
              } else {
                listEl.remove();
              }
              _this.editor.selection.setRangeAtStartOf(newBlockEl);
              return true;
            };
          })(this));
      this.editor.inputManager.addKeystrokeHandler('13', 'pre',
          (function (_this) {
            return function (e, $node) {
              var $p, breakNode, range;
              e.preventDefault();
              if (e.shiftKey) {
                $p = $('<p/>').append(_this.editor.util.phBr).insertAfter(
                    $node);
                _this.editor.selection.setRangeAtStartOf($p);
                return true;
              }
              range = _this.editor.selection.getRange();
              breakNode = null;
              range.deleteContents();
              if (!_this.editor.util.browser.msie
                  && _this.editor.selection.rangeAtEndOf($node)) {
                breakNode = document.createTextNode('\n\n');
                range.insertNode(breakNode);
                range.setEnd(breakNode, 1);
              } else {
                breakNode = document.createTextNode('\n');
                range.insertNode(breakNode);
                range.setStartAfter(breakNode);
              }
              range.collapse(false);
              _this.editor.selection.selectRange(range);
              return true;
            };
          })(this));
      this.editor.inputManager.addKeystrokeHandler('13', 'blockquote',
          (function (_this) {
            return function (e, $node) {
              var $closestBlock, range;
              $closestBlock = _this.editor.util.closestBlockEl();
              if (!($closestBlock.is('p') && !$closestBlock.next().length
                  && _this.editor.util.isEmptyNode($closestBlock))) {
                return;
              }
              $node.after($closestBlock);
              range = document.createRange();
              _this.editor.selection.setRangeAtStartOf($closestBlock, range);
              return true;
            };
          })(this));
      this.editor.inputManager.addKeystrokeHandler('8', 'li',
          (function (_this) {
            return function (e, $node) {
              var $br, $childList, $newLi, $prevChildList, $prevNode, $textNode,
                  range, text;
              $childList = $node.children('ul, ol');
              $prevNode = $node.prev('li');
              if (!($childList.length > 0 && $prevNode.length > 0)) {
                return false;
              }
              text = '';
              $textNode = null;
              $node.contents().each(function (i, n) {
                if (n.nodeType === 1 && /UL|OL/.test(n.nodeName)) {
                  return false;
                }
                if (n.nodeType === 1 && /BR/.test(n.nodeName)) {
                  return;
                }
                if (n.nodeType === 3 && n.nodeValue) {
                  text += n.nodeValue;
                } else if (n.nodeType === 1) {
                  text += $(n).text();
                }
                return $textNode = $(n);
              });
              if ($textNode && text.length === 1
                  && _this.editor.util.browser.firefox && !$textNode.next(
                      'br').length) {
                $br = $(_this.editor.util.phBr).insertAfter($textNode);
                $textNode.remove();
                _this.editor.selection.setRangeBefore($br);
                return true;
              } else if (text.length > 0) {
                return false;
              }
              range = document.createRange();
              $prevChildList = $prevNode.children('ul, ol');
              if ($prevChildList.length > 0) {
                $newLi = $('<li/>').append(_this.editor.util.phBr).appendTo(
                    $prevChildList);
                $prevChildList.append($childList.children('li'));
                $node.remove();
                _this.editor.selection.setRangeAtEndOf($newLi, range);
              } else {
                _this.editor.selection.setRangeAtEndOf($prevNode, range);
                $prevNode.append($childList);
                $node.remove();
                _this.editor.selection.selectRange(range);
              }
              return true;
            };
          })(this));
      this.editor.inputManager.addKeystrokeHandler('8', 'pre',
          (function (_this) {
            return function (e, $node) {
              var $newNode, codeStr, range;
              if (!_this.editor.selection.rangeAtStartOf($node)) {
                return;
              }
              codeStr = $node.html().replace('\n', '<br/>');
              $newNode = $('<p/>').append(
                  codeStr || _this.editor.util.phBr).insertAfter($node);
              $node.remove();
              range = document.createRange();
              _this.editor.selection.setRangeAtStartOf($newNode, range);
              return true;
            };
          })(this));
      return this.editor.inputManager.addKeystrokeHandler('8', 'blockquote',
          (function (_this) {
            return function (e, $node) {
              var $firstChild, range;
              if (!_this.editor.selection.rangeAtStartOf($node)) {
                return;
              }
              $firstChild = $node.children().first().unwrap();
              range = document.createRange();
              _this.editor.selection.setRangeAtStartOf($firstChild, range);
              return true;
            };
          })(this));
    };

    return Keystroke;

  })(SimpleModule);

  var UndoManager,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  UndoManager = (function (_super) {
    __extends(UndoManager, _super);

    function UndoManager() {
      return UndoManager.__super__.constructor.apply(this, arguments);
    }

    UndoManager.pluginName = 'UndoManager';

    UndoManager.prototype._index = -1;

    UndoManager.prototype._capacity = 50;

    UndoManager.prototype._timer = null;

    UndoManager.prototype._init = function () {
      var redoShortcut, undoShortcut;
      this.editor = this._module;
      this._stack = [];
      if (this.editor.util.os.mac) {
        undoShortcut = 'cmd+z';
        redoShortcut = 'shift+cmd+z';
      } else if (this.editor.util.os.win) {
        undoShortcut = 'ctrl+z';
        redoShortcut = 'ctrl+y';
      } else {
        undoShortcut = 'ctrl+z';
        redoShortcut = 'shift+ctrl+z';
      }
      this.editor.inputManager.addShortcut(undoShortcut, (function (_this) {
        return function (e) {
          e.preventDefault();
          _this.undo();
          return false;
        };
      })(this));
      this.editor.inputManager.addShortcut(redoShortcut, (function (_this) {
        return function (e) {
          e.preventDefault();
          _this.redo();
          return false;
        };
      })(this));
      return this.editor.on('valuechanged', (function (_this) {
        return function (e, src) {
          if (src === 'undo') {
            return;
          }
          if (_this._timer) {
            clearTimeout(_this._timer);
            _this._timer = null;
          }
          return _this._timer = setTimeout(function () {
            _this._pushUndoState();
            return _this._timer = null;
          }, 200);
        };
      })(this));
    };

    UndoManager.prototype._pushUndoState = function () {
      var currentState, html;
      if (this.editor.triggerHandler('pushundostate') === false) {
        return;
      }
      currentState = this.currentState();
      html = this.editor.body.html();
      if (currentState && currentState.html === html) {
        return;
      }
      this._index += 1;
      this._stack.length = this._index;
      this._stack.push({
        html: html,
        caret: this.caretPosition()
      });
      if (this._stack.length > this._capacity) {
        this._stack.shift();
        return this._index -= 1;
      }
    };

    UndoManager.prototype.currentState = function () {
      if (this._stack.length && this._index > -1) {
        return this._stack[this._index];
      } else {
        return null;
      }
    };

    UndoManager.prototype.undo = function () {
      var state;
      if (this._index < 1 || this._stack.length < 2) {
        return;
      }
      this.editor.hidePopover();
      this._index -= 1;
      state = this._stack[this._index];
      this.editor.body.html(state.html);
      this.caretPosition(state.caret);
      this.editor.body.find('.selected').removeClass('selected');
      this.editor.sync();
      return this.editor.trigger('valuechanged', ['undo']);
    };

    UndoManager.prototype.redo = function () {
      var state;
      if (this._index < 0 || this._stack.length < this._index + 2) {
        return;
      }
      this.editor.hidePopover();
      this._index += 1;
      state = this._stack[this._index];
      this.editor.body.html(state.html);
      this.caretPosition(state.caret);
      this.editor.body.find('.selected').removeClass('selected');
      this.editor.sync();
      return this.editor.trigger('valuechanged', ['undo']);
    };

    UndoManager.prototype.update = function () {
      var currentState, html;
      if (this._timer) {
        return;
      }
      currentState = this.currentState();
      if (!currentState) {
        return;
      }
      html = this.editor.body.html();
      currentState.html = html;
      return currentState.caret = this.caretPosition();
    };

    UndoManager.prototype._getNodeOffset = function (node, index) {
      var $parent, merging, offset;
      if (index) {
        $parent = $(node);
      } else {
        $parent = $(node).parent();
      }
      offset = 0;
      merging = false;
      $parent.contents().each((function (_this) {
        return function (i, child) {
          if (index === i || node === child) {
            return false;
          }
          if (child.nodeType === 3) {
            if (!merging) {
              offset += 1;
              merging = true;
            }
          } else {
            offset += 1;
            merging = false;
          }
          return null;
        };
      })(this));
      return offset;
    };

    UndoManager.prototype._getNodePosition = function (node, offset) {
      var position, prevNode;
      if (node.nodeType === 3) {
        prevNode = node.previousSibling;
        while (prevNode && prevNode.nodeType === 3) {
          node = prevNode;
          offset += this.editor.util.getNodeLength(prevNode);
          prevNode = prevNode.previousSibling;
        }
      } else {
        offset = this._getNodeOffset(node, offset);
      }
      position = [];
      position.unshift(offset);
      this.editor.util.traverseUp((function (_this) {
        return function (n) {
          return position.unshift(_this._getNodeOffset(n));
        };
      })(this), node);
      return position;
    };

    UndoManager.prototype._getNodeByPosition = function (position) {
      var child, childNodes, i, node, offset, _i, _len, _ref;
      node = this.editor.body[0];
      _ref = position.slice(0, position.length - 1);
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
        offset = _ref[i];
        childNodes = node.childNodes;
        if (offset > childNodes.length - 1) {
          if (i === position.length - 2 && $(node).is('pre')) {
            child = document.createTextNode('');
            node.appendChild(child);
            childNodes = node.childNodes;
          } else {
            node = null;
            break;
          }
        }
        node = childNodes[offset];
      }
      return node;
    };

    UndoManager.prototype.caretPosition = function (caret) {
      var endContainer, endOffset, range, startContainer, startOffset;
      if (!caret) {
        range = this.editor.selection.getRange();
        if (!(this.editor.inputManager.focused && (range != null))) {
          return {};
        }
        caret = {
          start: [],
          end: null,
          collapsed: true
        };
        caret.start = this._getNodePosition(range.startContainer,
            range.startOffset);
        if (!range.collapsed) {
          caret.end = this._getNodePosition(range.endContainer,
              range.endOffset);
          caret.collapsed = false;
        }
        return caret;
      } else {
        if (!this.editor.inputManager.focused) {
          this.editor.body.focus();
        }
        if (!caret.start) {
          this.editor.body.blur();
          return;
        }
        startContainer = this._getNodeByPosition(caret.start);
        startOffset = caret.start[caret.start.length - 1];
        if (caret.collapsed) {
          endContainer = startContainer;
          endOffset = startOffset;
        } else {
          endContainer = this._getNodeByPosition(caret.end);
          endOffset = caret.start[caret.start.length - 1];
        }
        if (!startContainer || !endContainer) {
          throw new Error('simditor: invalid caret state');
          return;
        }
        range = document.createRange();
        range.setStart(startContainer, startOffset);
        range.setEnd(endContainer, endOffset);
        return this.editor.selection.selectRange(range);
      }
    };

    return UndoManager;

  })(SimpleModule);

  var Util,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Util = (function (_super) {
    __extends(Util, _super);

    function Util() {
      return Util.__super__.constructor.apply(this, arguments);
    }

    Util.pluginName = 'Util';

    Util.prototype._init = function () {
      this.editor = this._module;
      if (this.browser.msie && this.browser.version < 11) {
        return this.phBr = '';
      }
    };

    Util.prototype.phBr = '<br/>';

    Util.prototype.os = (function () {
      var os;
      os = {};
      if (/Mac/.test(navigator.appVersion)) {
        os.mac = true;
      } else if (/Linux/.test(navigator.appVersion)) {
        os.linux = true;
      } else if (/Win/.test(navigator.appVersion)) {
        os.win = true;
      } else if (/X11/.test(navigator.appVersion)) {
        os.unix = true;
      }
      if (/Mobi/.test(navigator.appVersion)) {
        os.mobile = true;
      }
      return os;
    })();

    Util.prototype.browser = (function () {
      var chrome, firefox, ie, safari, ua, _ref, _ref1, _ref2, _ref3;
      ua = navigator.userAgent;
      ie = /(msie|trident)/i.test(ua);
      chrome = /chrome|crios/i.test(ua);
      safari = /safari/i.test(ua) && !chrome;
      firefox = /firefox/i.test(ua);
      if (ie) {
        return {
          msie: true,
          version: ((_ref = ua.match(/(msie |rv:)(\d+(\.\d+)?)/i)) != null
              ? _ref[2] : void 0) * 1
        };
      } else if (chrome) {
        return {
          webkit: true,
          chrome: true,
          version: ((_ref1 = ua.match(/(?:chrome|crios)\/(\d+(\.\d+)?)/i))
          != null ? _ref1[1] : void 0) * 1
        };
      } else if (safari) {
        return {
          webkit: true,
          safari: true,
          version: ((_ref2 = ua.match(/version\/(\d+(\.\d+)?)/i)) != null
              ? _ref2[1] : void 0) * 1
        };
      } else if (firefox) {
        return {
          mozilla: true,
          firefox: true,
          version: ((_ref3 = ua.match(/firefox\/(\d+(\.\d+)?)/i)) != null
              ? _ref3[1] : void 0) * 1
        };
      } else {
        return {};
      }
    })();

    Util.prototype.supportSelectionChange = (function () {
      var e, onselectionchange;
      onselectionchange = document.onselectionchange;
      if (onselectionchange !== void 0) {
        try {
          document.onselectionchange = 0;
          return document.onselectionchange === null;
        } catch (_error) {
          e = _error;
        } finally {
          document.onselectionchange = onselectionchange;
        }
      }
      return false;
    })();

    Util.prototype.reflow = function (el) {
      if (el == null) {
        el = document;
      }
      return $(el)[0].offsetHeight;
    };

    Util.prototype.metaKey = function (e) {
      var isMac;
      isMac = /Mac/.test(navigator.userAgent);
      if (isMac) {
        return e.metaKey;
      } else {
        return e.ctrlKey;
      }
    };

    Util.prototype.isEmptyNode = function (node) {
      var $node;
      $node = $(node);
      return $node.is(':empty') || (!$node.text() && !$node.find(
          ':not(br, span, div)').length);
    };

    Util.prototype.isBlockNode = function (node) {
      node = $(node)[0];
      if (!node || node.nodeType === 3) {
        return false;
      }
      return /^(div|p|ul|ol|li|blockquote|hr|pre|h1|h2|h3|h4|table)$/.test(
          node.nodeName.toLowerCase());
    };

    Util.prototype.closestBlockEl = function (node) {
      var $node, blockEl, range;
      if (node == null) {
        range = this.editor.selection.getRange();
        node = range != null ? range.commonAncestorContainer : void 0;
      }
      $node = $(node);
      if (!$node.length) {
        return null;
      }
      blockEl = $node.parentsUntil(this.editor.body).addBack();
      blockEl = blockEl.filter((function (_this) {
        return function (i) {
          return _this.isBlockNode(blockEl.eq(i));
        };
      })(this));
      if (blockEl.length) {
        return blockEl.last();
      } else {
        return null;
      }
    };

    Util.prototype.furthestNode = function (node, filter) {
      var $node, blockEl, range;
      if (node == null) {
        range = this.editor.selection.getRange();
        node = range != null ? range.commonAncestorContainer : void 0;
      }
      $node = $(node);
      if (!$node.length) {
        return null;
      }
      blockEl = $node.parentsUntil(this.editor.body).addBack();
      blockEl = blockEl.filter((function (_this) {
        return function (i) {
          var $n;
          $n = blockEl.eq(i);
          if ($.isFunction(filter)) {
            return filter($n);
          } else {
            return $n.is(filter);
          }
        };
      })(this));
      if (blockEl.length) {
        return blockEl.first();
      } else {
        return null;
      }
    };

    Util.prototype.furthestBlockEl = function (node) {
      return this.furthestNode(node, this.isBlockNode);
    };

    Util.prototype.getNodeLength = function (node) {
      switch (node.nodeType) {
        case 7:
        case 10:
          return 0;
        case 3:
        case 8:
          return node.length;
        default:
          return node.childNodes.length;
      }
    };

    Util.prototype.traverseUp = function (callback, node) {
      var n, nodes, range, result, _i, _len, _results;
      if (node == null) {
        range = this.editor.selection.getRange();
        node = range != null ? range.commonAncestorContainer : void 0;
      }
      if ((node == null) || !$.contains(this.editor.body[0], node)) {
        return false;
      }
      nodes = $(node).parentsUntil(this.editor.body).get();
      nodes.unshift(node);
      _results = [];
      for (_i = 0, _len = nodes.length; _i < _len; _i++) {
        n = nodes[_i];
        result = callback(n);
        if (result === false) {
          break;
        } else {
          _results.push(void 0);
        }
      }
      return _results;
    };

    Util.prototype.indent = function () {
      var $blockEl, $childList, $nextTd, $parentLi, $td, indentLevel, range,
          spaceNode, tagName, _ref;
      $blockEl = this.editor.util.closestBlockEl();
      if (!($blockEl && $blockEl.length > 0)) {
        return false;
      }
      if ($blockEl.is('pre')) {
        spaceNode = document.createTextNode('\u00A0\u00A0');
        this.editor.selection.insertNode(spaceNode);
      } else if ($blockEl.is('li')) {
        $parentLi = $blockEl.prev('li');
        if ($parentLi.length < 1) {
          return false;
        }
        this.editor.selection.save();
        tagName = $blockEl.parent()[0].tagName;
        $childList = $parentLi.children('ul, ol');
        if ($childList.length > 0) {
          $childList.append($blockEl);
        } else {
          $('<' + tagName + '/>').append($blockEl).appendTo($parentLi);
        }
        this.editor.selection.restore();
      } else if ($blockEl.is('p, h1, h2, h3, h4')) {
        indentLevel = (_ref = $blockEl.attr('data-indent')) != null ? _ref : 0;
        indentLevel = indentLevel * 1 + 1;
        if (indentLevel > 10) {
          indentLevel = 10;
        }
        $blockEl.attr('data-indent', indentLevel);
      } else if ($blockEl.is('table')) {
        range = this.editor.selection.getRange();
        $td = $(range.commonAncestorContainer).closest('td');
        $nextTd = $td.next('td');
        if (!($nextTd.length > 0)) {
          $nextTd = $td.parent('tr').next('tr').find('td:first');
        }
        if (!($td.length > 0 && $nextTd.length > 0)) {
          return false;
        }
        this.editor.selection.setRangeAtEndOf($nextTd);
      } else {
        spaceNode = document.createTextNode('\u00A0\u00A0\u00A0\u00A0');
        this.editor.selection.insertNode(spaceNode);
      }
      this.editor.trigger('valuechanged');
      return true;
    };

    Util.prototype.outdent = function () {
      var $blockEl, $parent, $parentLi, $prevTd, $td, button, indentLevel,
          range, _ref;
      $blockEl = this.editor.util.closestBlockEl();
      if (!($blockEl && $blockEl.length > 0)) {
        return false;
      }
      if ($blockEl.is('pre')) {
        return false;
      } else if ($blockEl.is('li')) {
        $parent = $blockEl.parent();
        $parentLi = $parent.parent('li');
        if ($parentLi.length < 1) {
          button = this.editor.toolbar.findButton(
              $parent[0].tagName.toLowerCase());
          if (button != null) {
            button.command();
          }
          return false;
        }
        this.editor.selection.save();
        if ($blockEl.next('li').length > 0) {
          $('<' + $parent[0].tagName + '/>').append(
              $blockEl.nextAll('li')).appendTo($blockEl);
        }
        $blockEl.insertAfter($parentLi);
        if ($parent.children('li').length < 1) {
          $parent.remove();
        }
        this.editor.selection.restore();
      } else if ($blockEl.is('p, h1, h2, h3, h4')) {
        indentLevel = (_ref = $blockEl.attr('data-indent')) != null ? _ref : 0;
        indentLevel = indentLevel * 1 - 1;
        if (indentLevel < 0) {
          indentLevel = 0;
        }
        $blockEl.attr('data-indent', indentLevel);
      } else if ($blockEl.is('table')) {
        range = this.editor.selection.getRange();
        $td = $(range.commonAncestorContainer).closest('td');
        $prevTd = $td.prev('td');
        if (!($prevTd.length > 0)) {
          $prevTd = $td.parent('tr').prev('tr').find('td:last');
        }
        if (!($td.length > 0 && $prevTd.length > 0)) {
          return false;
        }
        this.editor.selection.setRangeAtEndOf($prevTd);
      } else {
        return false;
      }
      this.editor.trigger('valuechanged');
      return true;
    };

    Util.prototype.dataURLtoBlob = function (dataURL) {
      var BlobBuilder, arrayBuffer, bb, byteString, hasArrayBufferViewSupport,
          hasBlobConstructor, i, intArray, mimeString, _i, _ref;
      hasBlobConstructor = window.Blob && (function () {
        var e;
        try {
          return Boolean(new Blob());
        } catch (_error) {
          e = _error;
          return false;
        }
      })();
      hasArrayBufferViewSupport = hasBlobConstructor && window.Uint8Array
          && (function () {
            var e;
            try {
              return new Blob([new Uint8Array(100)]).size === 100;
            } catch (_error) {
              e = _error;
              return false;
            }
          })();
      BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder
          || window.MozBlobBuilder || window.MSBlobBuilder;
      if (!((hasBlobConstructor || BlobBuilder) && window.atob
          && window.ArrayBuffer && window.Uint8Array)) {
        return false;
      }
      if (dataURL.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(dataURL.split(',')[1]);
      } else {
        byteString = decodeURIComponent(dataURL.split(',')[1]);
      }
      arrayBuffer = new ArrayBuffer(byteString.length);
      intArray = new Uint8Array(arrayBuffer);
      for (i = _i = 0, _ref = byteString.length;
          0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
        intArray[i] = byteString.charCodeAt(i);
      }
      mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
      if (hasBlobConstructor) {
        return new Blob([hasArrayBufferViewSupport ? intArray : arrayBuffer], {
          type: mimeString
        });
      }
      bb = new BlobBuilder();
      bb.append(arrayBuffer);
      return bb.getBlob(mimeString);
    };

    return Util;

  })(SimpleModule);

  var Toolbar,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Toolbar = (function (_super) {
    __extends(Toolbar, _super);

    function Toolbar() {
      return Toolbar.__super__.constructor.apply(this, arguments);
    }

    Toolbar.pluginName = 'Toolbar';

    Toolbar.prototype.opts = {
      toolbar: true,
      toolbarFloat: true,
      toolbarHidden: false,
      toolbarFloatOffset: 0
    };

    Toolbar.prototype._tpl = {
      wrapper: '<div class="simditor-toolbar"><ul></ul></div>',
      separator: '<li><span class="separator"></span></li>'
    };

    Toolbar.prototype._init = function () {
      var toolbarHeight;
      this.editor = this._module;
      if (!this.opts.toolbar) {
        return;
      }
      if (!$.isArray(this.opts.toolbar)) {
        this.opts.toolbar = ['bold', 'italic', 'underline', 'strikethrough',
          '|', 'ol', 'ul', 'blockquote', 'code', '|', 'link', 'image', '|',
          'indent', 'outdent'];
      }
      this._render();
      this.list.on('click', (function (_this) {
        return function (e) {
          return false;
        };
      })(this));
      this.wrapper.on('mousedown', (function (_this) {
        return function (e) {
          return _this.list.find('.menu-on').removeClass('.menu-on');
        };
      })(this));
      $(document).on('mousedown.simditor' + this.editor.id, (function (_this) {
        return function (e) {
          return _this.list.find('.menu-on').removeClass('.menu-on');
        };
      })(this));
      if (!this.opts.toolbarHidden && this.opts.toolbarFloat) {
        this.wrapper.width(this.wrapper.outerWidth());
        this.wrapper.css('top', this.opts.toolbarFloatOffset);
        toolbarHeight = this.wrapper.outerHeight();
        if (!this.editor.util.os.mobile) {
          $(window).on('resize.simditor-' + this.editor.id, (function (_this) {
            return function (e) {
              _this.wrapper.css('position', 'static');
              _this.editor.util.reflow(_this.wrapper);
              _this.wrapper.css('left', _this.wrapper.offset().left);
              return _this.wrapper.css('position', '');
            };
          })(this)).resize();
        }
        $(window).on('scroll.simditor-' + this.editor.id, (function (_this) {
          return function (e) {
            var bottomEdge, scrollTop, topEdge;
            topEdge = _this.editor.wrapper.offset().top;
            bottomEdge = topEdge + _this.editor.wrapper.outerHeight() - 80;
            scrollTop = $(document).scrollTop() + _this.opts.toolbarFloatOffset;
            if (scrollTop <= topEdge || scrollTop >= bottomEdge) {
              _this.editor.wrapper.removeClass('toolbar-floating').css(
                  'padding-top', '');
              if (_this.editor.util.os.mobile) {
                return _this.wrapper.css('top', _this.opts.toolbarFloatOffset);
              }
            } else {
              _this.editor.wrapper.addClass('toolbar-floating').css(
                  'padding-top', toolbarHeight);
              if (_this.editor.util.os.mobile) {
                return _this.wrapper.css('top',
                    scrollTop - topEdge + _this.opts.toolbarFloatOffset);
              }
            }
          };
        })(this));
      }
      this.editor.on('selectionchanged', (function (_this) {
        return function () {
          return _this.toolbarStatus();
        };
      })(this));
      this.editor.on('destroy', (function (_this) {
        return function () {
          return _this.buttons.length = 0;
        };
      })(this));
      return $(document).on('mousedown.simditor-' + this.editor.id,
          (function (_this) {
            return function (e) {
              return _this.list.find('li.menu-on').removeClass('menu-on');
            };
          })(this));
    };

    Toolbar.prototype._render = function () {
      var name, _i, _len, _ref;
      this.buttons = [];
      this.wrapper = $(this._tpl.wrapper).prependTo(this.editor.wrapper);
      this.list = this.wrapper.find('ul');
      _ref = this.opts.toolbar;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        name = _ref[_i];
        if (name === '|') {
          $(this._tpl.separator).appendTo(this.list);
          continue;
        }
        if (!this.constructor.buttons[name]) {
          throw new Error('simditor: invalid toolbar button "' + name + '"');
          continue;
        }
        this.buttons.push(new this.constructor.buttons[name]({
          editor: this.editor
        }));
      }
      if (this.opts.toolbarHidden) {
        return this.wrapper.hide();
      } else {
        return this.editor.placeholderEl.css('top', this.wrapper.outerHeight());
      }
    };

    Toolbar.prototype.toolbarStatus = function (name) {
      var buttons;
      if (!this.editor.inputManager.focused) {
        return;
      }
      buttons = this.buttons.slice(0);
      return this.editor.util.traverseUp((function (_this) {
        return function (node) {
          var button, i, removeButtons, _i, _j, _len, _len1;
          removeButtons = [];
          for (i = _i = 0, _len = buttons.length; _i < _len; i = ++_i) {
            button = buttons[i];
            if ((name != null) && button.name !== name) {
              continue;
            }
            if (!button.status || button.status($(node)) === true) {
              removeButtons.push(button);
            }
          }
          for (_j = 0, _len1 = removeButtons.length; _j < _len1; _j++) {
            button = removeButtons[_j];
            i = $.inArray(button, buttons);
            buttons.splice(i, 1);
          }
          if (buttons.length === 0) {
            return false;
          }
        };
      })(this));
    };

    Toolbar.prototype.findButton = function (name) {
      var button;
      button = this.list.find('.toolbar-item-' + name).data('button');
      return button != null ? button : null;
    };

    Toolbar.addButton = function (btn) {
      return this.buttons[btn.prototype.name] = btn;
    };

    Toolbar.buttons = {};

    return Toolbar;

  })(SimpleModule);

  var Simditor,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Simditor = (function (_super) {
    __extends(Simditor, _super);

    function Simditor() {
      return Simditor.__super__.constructor.apply(this, arguments);
    }

    Simditor.connect(Util);

    Simditor.connect(InputManager);

    Simditor.connect(UndoManager);

    Simditor.connect(Keystroke);

    Simditor.connect(Formatter);

    Simditor.connect(Selection);

    Simditor.connect(Toolbar);

    Simditor.count = 0;

    Simditor.prototype.opts = {
      textarea: null,
      placeholder: '',
      defaultImage: 'images/image.png',
      params: {},
      upload: false,
      tabIndent: true
    };

    Simditor.prototype._init = function () {
      var e, editor, form, uploadOpts;
      this.textarea = $(this.opts.textarea);
      this.opts.placeholder = this.opts.placeholder || this.textarea.attr(
          'placeholder');
      if (!this.textarea.length) {
        throw new Error('simditor: param textarea is required.');
        return;
      }
      editor = this.textarea.data('simditor');
      if (editor != null) {
        editor.destroy();
      }
      this.id = ++Simditor.count;
      this._render();
      if (this.opts.upload && simpleUploader) {
        uploadOpts = typeof this.opts.upload === 'object' ? this.opts.upload
            : {};
        this.uploader = simpleUploader(uploadOpts);
      }
      form = this.textarea.closest('form');
      if (form.length) {
        form.on('submit.simditor-' + this.id, (function (_this) {
          return function () {
            return _this.sync();
          };
        })(this));
        form.on('reset.simditor-' + this.id, (function (_this) {
          return function () {
            return _this.setValue('');
          };
        })(this));
      }
      this.on('initialized', (function (_this) {
        return function () {
          if (_this.opts.placeholder) {
            _this.on('valuechanged', function () {
              return _this._placeholder();
            });
          }
          return _this.setValue(_this.textarea.val().trim() || '');
        };
      })(this));
      if (this.util.browser.mozilla) {
        this.util.reflow();
        try {
          document.execCommand("enableObjectResizing", false, false);
          return document.execCommand("enableInlineTableEditing", false, false);
        } catch (_error) {
          e = _error;
        }
      }
    };

    Simditor.prototype._tpl = "<div class=\"simditor\">\n  <div class=\"simditor-wrapper\">\n    <div class=\"simditor-placeholder\"></div>\n    <div class=\"simditor-body\" contenteditable=\"true\">\n    </div>\n  </div>\n</div>";

    Simditor.prototype._render = function () {
      var key, val, _ref, _results;
      this.el = $(this._tpl).insertBefore(this.textarea);
      this.wrapper = this.el.find('.simditor-wrapper');
      this.body = this.wrapper.find('.simditor-body');
      this.placeholderEl = this.wrapper.find('.simditor-placeholder').append(
          this.opts.placeholder);
      this.el.append(this.textarea).data('simditor', this);
      this.textarea.data('simditor', this).hide().blur();
      this.body.attr('tabindex', this.textarea.attr('tabindex'));
      if (this.util.os.mac) {
        this.el.addClass('simditor-mac');
      } else if (this.util.os.linux) {
        this.el.addClass('simditor-linux');
      }
      if (this.util.os.mobile) {
        this.el.addClass('simditor-mobile');
      }
      if (this.opts.params) {
        _ref = this.opts.params;
        _results = [];
        for (key in _ref) {
          val = _ref[key];
          _results.push($('<input/>', {
            type: 'hidden',
            name: key,
            value: val
          }).insertAfter(this.textarea));
        }
        return _results;
      }
    };

    Simditor.prototype._placeholder = function () {
      var children, _ref;
      children = this.body.children();
      if (children.length === 0 || (children.length === 1
          && this.util.isEmptyNode(children) && ((_ref = children.data(
              'indent')) != null ? _ref : 0) < 1)) {
        return this.placeholderEl.show();
      } else {
        return this.placeholderEl.hide();
      }
    };

    Simditor.prototype.setValue = function (val) {
      this.hidePopover();
      this.textarea.val(val);
      this.body.html(val);
      this.formatter.format();
      this.formatter.decorate();
      this.util.reflow(this.body);
      this.inputManager.lastCaretPosition = null;
      return this.trigger('valuechanged');
    };

    Simditor.prototype.getValue = function () {
      return this.sync();
    };

    Simditor.prototype.sync = function () {
      var children, cloneBody, emptyP, firstP, lastP, val;
      cloneBody = this.body.clone();
      this.formatter.undecorate(cloneBody);
      this.formatter.format(cloneBody);
      this.formatter.autolink(cloneBody);
      children = cloneBody.children();
      lastP = children.last('p');
      firstP = children.first('p');
      while (lastP.is('p') && this.util.isEmptyNode(lastP)) {
        emptyP = lastP;
        lastP = lastP.prev('p');
        emptyP.remove();
      }
      while (firstP.is('p') && this.util.isEmptyNode(firstP)) {
        emptyP = firstP;
        firstP = lastP.next('p');
        emptyP.remove();
      }
      cloneBody.find('img.uploading').remove();
      val = $.trim(cloneBody.html());
      this.textarea.val(val);
      return val;
    };

    Simditor.prototype.focus = function () {
      var $blockEl, range;
      if (this.inputManager.lastCaretPosition) {
        return this.undoManager.caretPosition(
            this.inputManager.lastCaretPosition);
      } else {
        $blockEl = this.body.find('p, li, pre, h1, h2, h3, h4, td').first();
        if (!($blockEl.length > 0)) {
          return;
        }
        range = document.createRange();
        this.selection.setRangeAtStartOf($blockEl, range);
        return this.body.focus();
      }
    };

    Simditor.prototype.blur = function () {
      return this.body.blur();
    };

    Simditor.prototype.hidePopover = function () {
      return this.el.find('.simditor-popover').each((function (_this) {
        return function (i, popover) {
          popover = $(popover).data('popover');
          if (popover.active) {
            return popover.hide();
          }
        };
      })(this));
    };

    Simditor.prototype.destroy = function () {
      this.triggerHandler('destroy');
      this.textarea.closest('form').off('.simditor .simditor-' + this.id);
      this.selection.clear();
      this.inputManager.focused = false;
      this.textarea.insertBefore(this.el).hide().val('').removeData('simditor');
      this.el.remove();
      $(document).off('.simditor-' + this.id);
      $(window).off('.simditor-' + this.id);
      return this.off();
    };

    return Simditor;

  })(SimpleModule);

  Simditor.i18n = {
    'zh-CN': {
      'blockquote': '引用',
      'bold': '加粗文字',
      'code': '插入代码',
      'color': '文字颜色',
      'hr': '分隔线',
      'image': '插入图片',
      'localImage': '本地图片',
      'externalImage': '外链图片',
      'uploadImage': '上传图片',
      'uploadFailed': '上传失败了',
      'uploadError': '上传出错了',
      'imageUrl': '图片地址',
      'imageSize': '图片尺寸',
      'restoreImageSize': '还原图片尺寸',
      'uploading': '正在上传',
      'indent': '向右缩进',
      'outdent': '向左缩进',
      'italic': '斜体文字',
      'link': '插入链接',
      'text': '文本',
      'linkText': '链接文字',
      'linkUrl': '地址',
      'removeLink': '移除链接',
      'ol': '有序列表',
      'ul': '无序列表',
      'strikethrough': '删除线文字',
      'table': '表格',
      'deleteRow': '删除行',
      'insertRowAbove': '在上面插入行',
      'insertRowBelow': '在下面插入行',
      'deleteColumn': '删除列',
      'insertColumnLeft': '在左边插入列',
      'insertColumnRight': '在右边插入列',
      'deleteTable': '删除表格',
      'title': '标题',
      'normalText': '普通文本',
      'underline': '下划线文字'
    }
  };

  var Button,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __slice = [].slice;

  Button = (function (_super) {
    __extends(Button, _super);

    Button.prototype._tpl = {
      item: '<li><a tabindex="-1" unselectable="on" class="toolbar-item" href="javascript:;"><span></span></a></li>',
      menuWrapper: '<div class="toolbar-menu"></div>',
      menuItem: '<li><a tabindex="-1" unselectable="on" class="menu-item" href="javascript:;"><span></span></a></li>',
      separator: '<li><span class="separator"></span></li>'
    };

    Button.prototype.name = '';

    Button.prototype.icon = '';

    Button.prototype.title = '';

    Button.prototype.text = '';

    Button.prototype.htmlTag = '';

    Button.prototype.disableTag = '';

    Button.prototype.menu = false;

    Button.prototype.active = false;

    Button.prototype.disabled = false;

    Button.prototype.needFocus = true;

    Button.prototype.shortcut = null;

    function Button(opts) {
      this.editor = opts.editor;
      this.title = this._t(this.name);
      Button.__super__.constructor.call(this, opts);
    }

    Button.prototype._init = function () {
      var tag, _i, _len, _ref, _results;
      this.render();
      this.el.on('mousedown', (function (_this) {
        return function (e) {
          var exceed, param;
          e.preventDefault();
          if (_this.el.hasClass('disabled') || (_this.needFocus
              && !_this.editor.inputManager.focused)) {
            return false;
          }
          if (_this.menu) {
            _this.wrapper.toggleClass('menu-on').siblings('li').removeClass(
                'menu-on');
            if (_this.wrapper.is('.menu-on')) {
              exceed = _this.menuWrapper.offset().left
                  + _this.menuWrapper.outerWidth() + 5
                  - _this.editor.wrapper.offset().left
                  - _this.editor.wrapper.outerWidth();
              if (exceed > 0) {
                _this.menuWrapper.css({
                  'left': 'auto',
                  'right': 0
                });
              }
              _this.trigger('menuexpand');
            }
            return false;
          }
          param = _this.el.data('param');
          _this.command(param);
          return false;
        };
      })(this));
      this.wrapper.on('click', 'a.menu-item', (function (_this) {
        return function (e) {
          var btn, param;
          e.preventDefault();
          btn = $(e.currentTarget);
          _this.wrapper.removeClass('menu-on');
          if (btn.hasClass('disabled') || (_this.needFocus
              && !_this.editor.inputManager.focused)) {
            return false;
          }
          _this.editor.toolbar.wrapper.removeClass('menu-on');
          param = btn.data('param');
          _this.command(param);
          return false;
        };
      })(this));
      this.wrapper.on('mousedown', 'a.menu-item', (function (_this) {
        return function (e) {
          return false;
        };
      })(this));
      this.editor.on('blur', (function (_this) {
        return function () {
          _this.setActive(false);
          return _this.setDisabled(false);
        };
      })(this));
      if (this.shortcut != null) {
        this.editor.inputManager.addShortcut(this.shortcut, (function (_this) {
          return function (e) {
            _this.el.mousedown();
            return false;
          };
        })(this));
      }
      _ref = this.htmlTag.split(',');
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        tag = _ref[_i];
        tag = $.trim(tag);
        if (tag && $.inArray(tag, this.editor.formatter._allowedTags) < 0) {
          _results.push(this.editor.formatter._allowedTags.push(tag));
        } else {
          _results.push(void 0);
        }
      }
      return _results;
    };

    Button.prototype.render = function () {
      this.wrapper = $(this._tpl.item).appendTo(this.editor.toolbar.list);
      this.el = this.wrapper.find('a.toolbar-item');
      this.el.attr('title', this.title).addClass(
          'toolbar-item-' + this.name).data('button', this);
      this.el.find('span').addClass(this.icon ? 'fa fa-' + this.icon : '').text(
          this.text);
      if (!this.menu) {
        return;
      }
      this.menuWrapper = $(this._tpl.menuWrapper).appendTo(this.wrapper);
      this.menuWrapper.addClass('toolbar-menu-' + this.name);
      return this.renderMenu();
    };

    Button.prototype.renderMenu = function () {
      var $menuBtntnEl, $menuItemEl, menuItem, _i, _len, _ref, _ref1, _results;
      if (!$.isArray(this.menu)) {
        return;
      }
      this.menuEl = $('<ul/>').appendTo(this.menuWrapper);
      _ref = this.menu;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        menuItem = _ref[_i];
        if (menuItem === '|') {
          $(this._tpl.separator).appendTo(this.menuEl);
          continue;
        }
        $menuItemEl = $(this._tpl.menuItem).appendTo(this.menuEl);
        _results.push($menuBtntnEl = $menuItemEl.find('a.menu-item').attr({
          'title': (_ref1 = menuItem.title) != null ? _ref1 : menuItem.text,
          'data-param': menuItem.param
        }).addClass('menu-item-' + menuItem.name).find('span').text(
            menuItem.text));
      }
      return _results;
    };

    Button.prototype.setActive = function (active) {
      if (active === this.active) {
        return;
      }
      this.active = active;
      this.el.toggleClass('active', this.active);
      return this.editor.toolbar.trigger('buttonstatus', [this]);
    };

    Button.prototype.setDisabled = function (disabled) {
      if (disabled === this.disabled) {
        return;
      }
      this.disabled = disabled;
      this.el.toggleClass('disabled', this.disabled);
      return this.editor.toolbar.trigger('buttonstatus', [this]);
    };

    Button.prototype.status = function ($node) {
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      if ($node != null) {
        this.setActive($node.is(this.htmlTag));
      }
      return this.active;
    };

    Button.prototype.command = function (param) {
    };

    Button.prototype._t = function () {
      var args, result, _ref;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      result = Button.__super__._t.apply(this, args);
      if (!result) {
        result = (_ref = this.editor)._t.apply(_ref, args);
      }
      return result;
    };

    return Button;

  })(SimpleModule);

  Simditor.Button = Button;

  var Popover,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  Popover = (function (_super) {
    __extends(Popover, _super);

    Popover.prototype.offset = {
      top: 4,
      left: 0
    };

    Popover.prototype.target = null;

    Popover.prototype.active = false;

    function Popover(opts) {
      this.button = opts.button;
      this.editor = opts.button.editor;
      Popover.__super__.constructor.call(this, opts);
    }

    Popover.prototype._init = function () {
      this.el = $('<div class="simditor-popover"></div>').appendTo(
          this.editor.el).data('popover', this);
      this.render();
      this.el.on('mouseenter', (function (_this) {
        return function (e) {
          return _this.el.addClass('hover');
        };
      })(this));
      return this.el.on('mouseleave', (function (_this) {
        return function (e) {
          return _this.el.removeClass('hover');
        };
      })(this));
    };

    Popover.prototype.render = function () {
    };

    Popover.prototype.show = function ($target, position) {
      if (position == null) {
        position = 'bottom';
      }
      if ($target == null) {
        return;
      }
      this.el.siblings('.simditor-popover').each((function (_this) {
        return function (i, popover) {
          popover = $(popover).data('popover');
          if (popover.active) {
            return popover.hide();
          }
        };
      })(this));
      this.target = $target.addClass('selected');
      if (this.active) {
        this.refresh(position);
        return this.trigger('popovershow');
      } else {
        this.active = true;
        this.el.css({
          left: -9999
        }).show();
        return setTimeout((function (_this) {
          return function () {
            _this.refresh(position);
            return _this.trigger('popovershow');
          };
        })(this), 0);
      }
    };

    Popover.prototype.hide = function () {
      if (!this.active) {
        return;
      }
      if (this.target) {
        this.target.removeClass('selected');
      }
      this.target = null;
      this.active = false;
      this.el.hide();
      return this.trigger('popoverhide');
    };

    Popover.prototype.refresh = function (position) {
      var editorOffset, left, targetH, targetOffset, top;
      if (position == null) {
        position = 'bottom';
      }
      if (!this.active) {
        return;
      }
      editorOffset = this.editor.el.offset();
      targetOffset = this.target.offset();
      targetH = this.target.outerHeight();
      if (position === 'bottom') {
        top = targetOffset.top - editorOffset.top + targetH;
      } else if (position === 'top') {
        top = targetOffset.top - editorOffset.top - this.el.height();
      }
      left = Math.min(targetOffset.left - editorOffset.left,
          this.editor.wrapper.width() - this.el.outerWidth() - 10);
      return this.el.css({
        top: top + this.offset.top,
        left: left + this.offset.left
      });
    };

    Popover.prototype.destroy = function () {
      this.target = null;
      this.active = false;
      this.editor.off('.linkpopover');
      return this.el.remove();
    };

    return Popover;

  })(SimpleModule);

  Simditor.Popover = Popover;

  var TitleButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  TitleButton = (function (_super) {
    __extends(TitleButton, _super);

    function TitleButton() {
      return TitleButton.__super__.constructor.apply(this, arguments);
    }

    TitleButton.prototype.name = 'title';

    TitleButton.prototype.htmlTag = 'h1, h2, h3, h4';

    TitleButton.prototype.disableTag = 'pre, table';

    TitleButton.prototype._init = function () {
      this.menu = [
        {
          name: 'normal',
          text: this._t('normalText'),
          param: 'p'
        }, '|', {
          name: 'h1',
          text: this._t('title') + ' 1',
          param: 'h1'
        }, {
          name: 'h2',
          text: this._t('title') + ' 2',
          param: 'h2'
        }, {
          name: 'h3',
          text: this._t('title') + ' 3',
          param: 'h3'
        }, {
          name: 'h4',
          text: this._t('title') + ' 4',
          param: 'h4'
        }, {
          name: 'h5',
          text: this._t('title') + ' 5',
          param: 'h5'
        }
      ];
      return TitleButton.__super__._init.call(this);
    };

    TitleButton.prototype.setActive = function (active, param) {
      TitleButton.__super__.setActive.call(this, active);
      this.el.removeClass('active-p active-h1 active-h2 active-h3');
      if (active) {
        return this.el.addClass('active active-' + param);
      }
    };

    TitleButton.prototype.status = function ($node) {
      var param, _ref;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      if ($node != null) {
        param = (_ref = $node[0].tagName) != null ? _ref.toLowerCase() : void 0;
        this.setActive($node.is(this.htmlTag), param);
      }
      return this.active;
    };

    TitleButton.prototype.command = function (param) {
      var $contents, $endBlock, $startBlock, endNode, node, range, results,
          startNode, _i, _len, _ref;
      range = this.editor.selection.getRange();
      startNode = range.startContainer;
      endNode = range.endContainer;
      $startBlock = this.editor.util.closestBlockEl(startNode);
      $endBlock = this.editor.util.closestBlockEl(endNode);
      this.editor.selection.save();
      range.setStartBefore($startBlock[0]);
      range.setEndAfter($endBlock[0]);
      $contents = $(range.extractContents());
      results = [];
      $contents.children().each((function (_this) {
        return function (i, el) {
          var c, converted, _i, _len, _results;
          converted = _this._convertEl(el, param);
          _results = [];
          for (_i = 0, _len = converted.length; _i < _len; _i++) {
            c = converted[_i];
            _results.push(results.push(c));
          }
          return _results;
        };
      })(this));
      _ref = results.reverse();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        node = _ref[_i];
        range.insertNode(node[0]);
      }
      this.editor.selection.restore();
      return this.editor.trigger('valuechanged');
    };

    TitleButton.prototype._convertEl = function (el, param) {
      var $block, $el, results;
      $el = $(el);
      results = [];
      if ($el.is(param)) {
        results.push($el);
      } else {
        $block = $('<' + param + '/>').append($el.contents());
        results.push($block);
      }
      return results;
    };

    return TitleButton;

  })(Button);

  Simditor.Toolbar.addButton(TitleButton);

  var BoldButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  BoldButton = (function (_super) {
    __extends(BoldButton, _super);

    function BoldButton() {
      return BoldButton.__super__.constructor.apply(this, arguments);
    }

    BoldButton.prototype.name = 'bold';

    BoldButton.prototype.icon = 'bold';

    BoldButton.prototype.htmlTag = 'b, strong';

    BoldButton.prototype.disableTag = 'pre';

    BoldButton.prototype.shortcut = 'cmd+b';

    BoldButton.prototype._init = function () {
      if (this.editor.util.os.mac) {
        this.title = this.title + ' ( Cmd + b )';
      } else {
        this.title = this.title + ' ( Ctrl + b )';
        this.shortcut = 'ctrl+b';
      }
      return BoldButton.__super__._init.call(this);
    };

    BoldButton.prototype.status = function ($node) {
      var active;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      active = document.queryCommandState('bold') === true;
      this.setActive(active);
      return active;
    };

    BoldButton.prototype.command = function () {
      document.execCommand('bold');
      this.editor.trigger('valuechanged');
      return $(document).trigger('selectionchange');
    };

    return BoldButton;

  })(Button);

  Simditor.Toolbar.addButton(BoldButton);

  var ItalicButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  ItalicButton = (function (_super) {
    __extends(ItalicButton, _super);

    function ItalicButton() {
      return ItalicButton.__super__.constructor.apply(this, arguments);
    }

    ItalicButton.prototype.name = 'italic';

    ItalicButton.prototype.icon = 'italic';

    ItalicButton.prototype.htmlTag = 'i';

    ItalicButton.prototype.disableTag = 'pre';

    ItalicButton.prototype.shortcut = 'cmd+i';

    ItalicButton.prototype._init = function () {
      if (this.editor.util.os.mac) {
        this.title = this.title + ' ( Cmd + i )';
      } else {
        this.title = this.title + ' ( Ctrl + i )';
        this.shortcut = 'ctrl+i';
      }
      return ItalicButton.__super__._init.call(this);
    };

    ItalicButton.prototype.status = function ($node) {
      var active;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return this.disabled;
      }
      active = document.queryCommandState('italic') === true;
      this.setActive(active);
      return active;
    };

    ItalicButton.prototype.command = function () {
      document.execCommand('italic');
      this.editor.trigger('valuechanged');
      return $(document).trigger('selectionchange');
    };

    return ItalicButton;

  })(Button);

  Simditor.Toolbar.addButton(ItalicButton);

  var UnderlineButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  UnderlineButton = (function (_super) {
    __extends(UnderlineButton, _super);

    function UnderlineButton() {
      return UnderlineButton.__super__.constructor.apply(this, arguments);
    }

    UnderlineButton.prototype.name = 'underline';

    UnderlineButton.prototype.icon = 'underline';

    UnderlineButton.prototype.htmlTag = 'u';

    UnderlineButton.prototype.disableTag = 'pre';

    UnderlineButton.prototype.shortcut = 'cmd+u';

    UnderlineButton.prototype.render = function () {
      if (this.editor.util.os.mac) {
        this.title = this.title + ' ( Cmd + u )';
      } else {
        this.title = this.title + ' ( Ctrl + u )';
        this.shortcut = 'ctrl+u';
      }
      return UnderlineButton.__super__.render.call(this);
    };

    UnderlineButton.prototype.status = function ($node) {
      var active;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return this.disabled;
      }
      active = document.queryCommandState('underline') === true;
      this.setActive(active);
      return active;
    };

    UnderlineButton.prototype.command = function () {
      document.execCommand('underline');
      this.editor.trigger('valuechanged');
      return $(document).trigger('selectionchange');
    };

    return UnderlineButton;

  })(Button);

  Simditor.Toolbar.addButton(UnderlineButton);

  var ColorButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __slice = [].slice;

  ColorButton = (function (_super) {
    __extends(ColorButton, _super);

    function ColorButton() {
      return ColorButton.__super__.constructor.apply(this, arguments);
    }

    ColorButton.prototype.name = 'color';

    ColorButton.prototype.icon = 'font';

    ColorButton.prototype.disableTag = 'pre';

    ColorButton.prototype.menu = true;

    ColorButton.prototype.render = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return ColorButton.__super__.render.apply(this, args);
    };

    ColorButton.prototype.renderMenu = function () {
      $('<ul class="color-list">\n  <li><a href="javascript:;" class="font-color font-color-1" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-2" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-3" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-4" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-5" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-6" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-7" data-color=""></a></li>\n  <li><a href="javascript:;" class="font-color font-color-default" data-color=""></a></li>\n</ul>').appendTo(
          this.menuWrapper);
      this.menuWrapper.on('mousedown', '.color-list', function (e) {
        return false;
      });
      return this.menuWrapper.on('click', '.font-color', (function (_this) {
        return function (e) {
          var $link, $p, hex, rgb;
          _this.wrapper.removeClass('menu-on');
          $link = $(e.currentTarget);
          if ($link.hasClass('font-color-default')) {
            $p = _this.editor.body.find('p, li');
            if (!($p.length > 0)) {
              return;
            }
            rgb = window.getComputedStyle($p[0], null).getPropertyValue(
                'color');
            hex = _this._convertRgbToHex(rgb);
          } else {
            rgb = window.getComputedStyle($link[0], null).getPropertyValue(
                'background-color');
            hex = _this._convertRgbToHex(rgb);
          }
          if (!hex) {
            return;
          }
          document.execCommand('foreColor', false, hex);
          return _this.editor.trigger('valuechanged');
        };
      })(this));
    };

    ColorButton.prototype._convertRgbToHex = function (rgb) {
      var match, re, rgbToHex;
      re = /rgb\((\d+),\s?(\d+),\s?(\d+)\)/g;
      match = re.exec(rgb);
      if (!match) {
        return '';
      }
      rgbToHex = function (r, g, b) {
        var componentToHex;
        componentToHex = function (c) {
          var hex;
          hex = c.toString(16);
          if (hex.length === 1) {
            return '0' + hex;
          } else {
            return hex;
          }
        };
        return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
      };
      return rgbToHex(match[1] * 1, match[2] * 1, match[3] * 1);
    };

    return ColorButton;

  })(Button);

  Simditor.Toolbar.addButton(ColorButton);

  var ListButton, OrderListButton, UnorderListButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  ListButton = (function (_super) {
    __extends(ListButton, _super);

    function ListButton() {
      return ListButton.__super__.constructor.apply(this, arguments);
    }

    ListButton.prototype.type = '';

    ListButton.prototype.disableTag = 'pre, table';

    ListButton.prototype.status = function ($node) {
      var anotherType;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      if ($node == null) {
        return this.active;
      }
      anotherType = this.type === 'ul' ? 'ol' : 'ul';
      if ($node.is(anotherType)) {
        this.setActive(false);
        return true;
      } else {
        this.setActive($node.is(this.htmlTag));
        return this.active;
      }
    };

    ListButton.prototype.command = function (param) {
      var $contents, $endBlock, $furthestEnd, $furthestStart, $parent,
          $startBlock, endLevel, endNode, getListLevel, node, range, results,
          startLevel, startNode, _i, _len, _ref;
      range = this.editor.selection.getRange();
      startNode = range.startContainer;
      endNode = range.endContainer;
      $startBlock = this.editor.util.closestBlockEl(startNode);
      $endBlock = this.editor.util.closestBlockEl(endNode);
      this.editor.selection.save();
      range.setStartBefore($startBlock[0]);
      range.setEndAfter($endBlock[0]);
      if ($startBlock.is('li') && $endBlock.is('li')) {
        $furthestStart = this.editor.util.furthestNode($startBlock, 'ul, ol');
        $furthestEnd = this.editor.util.furthestNode($endBlock, 'ul, ol');
        if ($furthestStart.is($furthestEnd)) {
          getListLevel = function ($li) {
            var lvl;
            lvl = 1;
            while (!$li.parent().is($furthestStart)) {
              lvl += 1;
              $li = $li.parent();
            }
            return lvl;
          };
          startLevel = getListLevel($startBlock);
          endLevel = getListLevel($endBlock);
          if (startLevel > endLevel) {
            $parent = $endBlock.parent();
          } else {
            $parent = $startBlock.parent();
          }
          range.setStartBefore($parent[0]);
          range.setEndAfter($parent[0]);
        } else {
          range.setStartBefore($furthestStart[0]);
          range.setEndAfter($furthestEnd[0]);
        }
      }
      $contents = $(range.extractContents());
      results = [];
      $contents.children().each((function (_this) {
        return function (i, el) {
          var c, converted, _i, _len, _results;
          converted = _this._convertEl(el);
          _results = [];
          for (_i = 0, _len = converted.length; _i < _len; _i++) {
            c = converted[_i];
            if (results.length && results[results.length - 1].is(_this.type)
                && c.is(_this.type)) {
              _results.push(results[results.length - 1].append(c.children()));
            } else {
              _results.push(results.push(c));
            }
          }
          return _results;
        };
      })(this));
      _ref = results.reverse();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        node = _ref[_i];
        range.insertNode(node[0]);
      }
      this.editor.selection.restore();
      return this.editor.trigger('valuechanged');
    };

    ListButton.prototype._convertEl = function (el) {
      var $el, anotherType, block, child, children, results, _i, _len, _ref;
      $el = $(el);
      results = [];
      anotherType = this.type === 'ul' ? 'ol' : 'ul';
      if ($el.is(this.type)) {
        $el.children('li').each((function (_this) {
          return function (i, li) {
            var $childList, $li, block;
            $li = $(li);
            $childList = $li.children('ul, ol').remove();
            block = $('<p/>').append($(li).html() || _this.editor.util.phBr);
            results.push(block);
            if ($childList.length > 0) {
              return results.push($childList);
            }
          };
        })(this));
      } else if ($el.is(anotherType)) {
        block = $('<' + this.type + '/>').append($el.html());
        results.push(block);
      } else if ($el.is('blockquote')) {
        _ref = $el.children().get();
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          child = _ref[_i];
          children = this._convertEl(child);
        }
        $.merge(results, children);
      } else if ($el.is('table')) {

      } else {
        block = $('<' + this.type + '><li></li></' + this.type + '>');
        block.find('li').append($el.html() || this.editor.util.phBr);
        results.push(block);
      }
      return results;
    };

    return ListButton;

  })(Button);

  OrderListButton = (function (_super) {
    __extends(OrderListButton, _super);

    function OrderListButton() {
      return OrderListButton.__super__.constructor.apply(this, arguments);
    }

    OrderListButton.prototype.type = 'ol';

    OrderListButton.prototype.name = 'ol';

    OrderListButton.prototype.icon = 'list-ol';

    OrderListButton.prototype.htmlTag = 'ol';

    OrderListButton.prototype.shortcut = 'cmd+/';

    OrderListButton.prototype._init = function () {
      if (this.editor.util.os.mac) {
        this.title = this.title + ' ( Cmd + / )';
      } else {
        this.title = this.title + ' ( ctrl + / )';
        this.shortcut = 'ctrl+/';
      }
      return OrderListButton.__super__._init.call(this);
    };

    return OrderListButton;

  })(ListButton);

  UnorderListButton = (function (_super) {
    __extends(UnorderListButton, _super);

    function UnorderListButton() {
      return UnorderListButton.__super__.constructor.apply(this, arguments);
    }

    UnorderListButton.prototype.type = 'ul';

    UnorderListButton.prototype.name = 'ul';

    UnorderListButton.prototype.icon = 'list-ul';

    UnorderListButton.prototype.htmlTag = 'ul';

    UnorderListButton.prototype.shortcut = 'cmd+.';

    UnorderListButton.prototype._init = function () {
      if (this.editor.util.os.mac) {
        this.title = this.title + ' ( Cmd + . )';
      } else {
        this.title = this.title + ' ( Ctrl + . )';
        this.shortcut = 'ctrl+.';
      }
      return UnorderListButton.__super__._init.call(this);
    };

    return UnorderListButton;

  })(ListButton);

  Simditor.Toolbar.addButton(OrderListButton);

  Simditor.Toolbar.addButton(UnorderListButton);

  var BlockquoteButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  BlockquoteButton = (function (_super) {
    __extends(BlockquoteButton, _super);

    function BlockquoteButton() {
      return BlockquoteButton.__super__.constructor.apply(this, arguments);
    }

    BlockquoteButton.prototype.name = 'blockquote';

    BlockquoteButton.prototype.icon = 'quote-left';

    BlockquoteButton.prototype.htmlTag = 'blockquote';

    BlockquoteButton.prototype.disableTag = 'pre, table';

    BlockquoteButton.prototype.command = function () {
      var $contents, $endBlock, $startBlock, endNode, node, range, results,
          startNode, _i, _len, _ref;
      range = this.editor.selection.getRange();
      startNode = range.startContainer;
      endNode = range.endContainer;
      $startBlock = this.editor.util.furthestBlockEl(startNode);
      $endBlock = this.editor.util.furthestBlockEl(endNode);
      this.editor.selection.save();
      range.setStartBefore($startBlock[0]);
      range.setEndAfter($endBlock[0]);
      $contents = $(range.extractContents());
      results = [];
      $contents.children().each((function (_this) {
        return function (i, el) {
          var c, converted, _i, _len, _results;
          converted = _this._convertEl(el);
          _results = [];
          for (_i = 0, _len = converted.length; _i < _len; _i++) {
            c = converted[_i];
            if (results.length && results[results.length - 1].is(_this.htmlTag)
                && c.is(_this.htmlTag)) {
              _results.push(results[results.length - 1].append(c.children()));
            } else {
              _results.push(results.push(c));
            }
          }
          return _results;
        };
      })(this));
      _ref = results.reverse();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        node = _ref[_i];
        range.insertNode(node[0]);
      }
      this.editor.selection.restore();
      return this.editor.trigger('valuechanged');
    };

    BlockquoteButton.prototype._convertEl = function (el) {
      var $el, block, results;
      $el = $(el);
      results = [];
      if ($el.is(this.htmlTag)) {
        $el.children().each((function (_this) {
          return function (i, node) {
            return results.push($(node));
          };
        })(this));
      } else {
        block = $('<' + this.htmlTag + '/>').append($el);
        results.push(block);
      }
      return results;
    };

    return BlockquoteButton;

  })(Button);

  Simditor.Toolbar.addButton(BlockquoteButton);

  var CodeButton, CodePopover,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __slice = [].slice;

  CodeButton = (function (_super) {
    __extends(CodeButton, _super);

    function CodeButton() {
      return CodeButton.__super__.constructor.apply(this, arguments);
    }

    CodeButton.prototype.name = 'code';

    CodeButton.prototype.icon = 'code';

    CodeButton.prototype.htmlTag = 'pre';

    CodeButton.prototype.disableTag = 'li, table';

    CodeButton.prototype._init = function () {
      CodeButton.__super__._init.call(this);
      this.editor.on('decorate', (function (_this) {
        return function (e, $el) {
          return $el.find('pre').each(function (i, pre) {
            return _this.decorate($(pre));
          });
        };
      })(this));
      return this.editor.on('undecorate', (function (_this) {
        return function (e, $el) {
          return $el.find('pre').each(function (i, pre) {
            return _this.undecorate($(pre));
          });
        };
      })(this));
    };

    CodeButton.prototype.render = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      CodeButton.__super__.render.apply(this, args);
      return this.popover = new CodePopover({
        button: this
      });
    };

    CodeButton.prototype.status = function ($node) {
      var result;
      result = CodeButton.__super__.status.call(this, $node);
      if (this.active) {
        this.popover.show($node);
      } else if (this.editor.util.isBlockNode($node)) {
        this.popover.hide();
      }
      return result;
    };

    CodeButton.prototype.decorate = function ($pre) {
      var lang;
      lang = $pre.attr('data-lang');
      $pre.removeClass();
      if (lang && lang !== -1) {
        return $pre.addClass('lang-' + lang);
      }
    };

    CodeButton.prototype.undecorate = function ($pre) {
      var lang;
      lang = $pre.attr('data-lang');
      $pre.removeClass();
      if (lang && lang !== -1) {
        return $pre.addClass('lang-' + lang);
      }
    };

    CodeButton.prototype.command = function () {
      var $contents, $endBlock, $startBlock, endNode, node, range, results,
          startNode, _i, _len, _ref;
      range = this.editor.selection.getRange();
      startNode = range.startContainer;
      endNode = range.endContainer;
      $startBlock = this.editor.util.closestBlockEl(startNode);
      $endBlock = this.editor.util.closestBlockEl(endNode);
      range.setStartBefore($startBlock[0]);
      range.setEndAfter($endBlock[0]);
      $contents = $(range.extractContents());
      results = [];
      $contents.children().each((function (_this) {
        return function (i, el) {
          var c, converted, _i, _len, _results;
          converted = _this._convertEl(el);
          _results = [];
          for (_i = 0, _len = converted.length; _i < _len; _i++) {
            c = converted[_i];
            if (results.length && results[results.length - 1].is(_this.htmlTag)
                && c.is(_this.htmlTag)) {
              _results.push(results[results.length - 1].append(c.contents()));
            } else {
              _results.push(results.push(c));
            }
          }
          return _results;
        };
      })(this));
      _ref = results.reverse();
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        node = _ref[_i];
        range.insertNode(node[0]);
      }
      this.editor.selection.setRangeAtEndOf(results[0]);
      return this.editor.trigger('valuechanged');
    };

    CodeButton.prototype._convertEl = function (el) {
      var $el, block, codeStr, results;
      $el = $(el);
      results = [];
      if ($el.is(this.htmlTag)) {
        block = $('<p/>').append($el.html().replace('\n', '<br/>'));
        results.push(block);
      } else {
        if (!$el.text() && $el.children().length === 1 && $el.children().is(
            'br')) {
          codeStr = '\n';
        } else {
          codeStr = this.editor.formatter.clearHtml($el);
        }
        block = $('<' + this.htmlTag + '/>').text(codeStr);
        results.push(block);
      }
      return results;
    };

    return CodeButton;

  })(Button);

  CodePopover = (function (_super) {
    __extends(CodePopover, _super);

    function CodePopover() {
      return CodePopover.__super__.constructor.apply(this, arguments);
    }

    CodePopover.prototype._tpl = "<div class=\"code-settings\">\n  <div class=\"settings-field\">\n    <select class=\"select-lang\">\n      <option value=\"-1\">选择程序语言</option>\n      <option value=\"bash\">Bash</option>\n      <option value=\"c++\">C++</option>\n      <option value=\"cs\">C#</option>\n      <option value=\"css\">CSS</option>\n      <option value=\"erlang\">Erlang</option>\n      <option value=\"less\">Less</option>\n      <option value=\"scss\">Sass</option>\n      <option value=\"diff\">Diff</option>\n      <option value=\"coffeeScript\">CoffeeScript</option>\n      <option value=\"html\">Html,XML</option>\n      <option value=\"json\">JSON</option>\n      <option value=\"java\">Java</option>\n      <option value=\"js\">JavaScript</option>\n      <option value=\"markdown\">Markdown</option>\n      <option value=\"oc\">Objective C</option>\n      <option value=\"php\">PHP</option>\n      <option value=\"perl\">Perl</option>\n      <option value=\"python\">Python</option>\n      <option value=\"ruby\">Ruby</option>\n      <option value=\"sql\">SQL</option>\n    </select>\n  </div>\n</div>";

    CodePopover.prototype.render = function () {
      this.el.addClass('code-popover').append(this._tpl);
      this.selectEl = this.el.find('.select-lang');
      return this.selectEl.on('change', (function (_this) {
        return function (e) {
          var selected;
          _this.lang = _this.selectEl.val();
          selected = _this.target.hasClass('selected');
          _this.target.removeClass().removeAttr('data-lang');
          if (_this.lang !== -1) {
            _this.target.addClass('lang-' + _this.lang);
            _this.target.attr('data-lang', _this.lang);
          }
          if (selected) {
            return _this.target.addClass('selected');
          }
        };
      })(this));
    };

    CodePopover.prototype.show = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      CodePopover.__super__.show.apply(this, args);
      this.lang = this.target.attr('data-lang');
      if (this.lang != null) {
        return this.selectEl.val(this.lang);
      } else {
        return this.selectEl.val(-1);
      }
    };

    return CodePopover;

  })(Popover);

  Simditor.Toolbar.addButton(CodeButton);

  var LinkButton, LinkPopover,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __slice = [].slice;

  LinkButton = (function (_super) {
    __extends(LinkButton, _super);

    function LinkButton() {
      return LinkButton.__super__.constructor.apply(this, arguments);
    }

    LinkButton.prototype.name = 'link';

    LinkButton.prototype.icon = 'link';

    LinkButton.prototype.htmlTag = 'a';

    LinkButton.prototype.disableTag = 'pre';

    LinkButton.prototype.render = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      LinkButton.__super__.render.apply(this, args);
      return this.popover = new LinkPopover({
        button: this
      });
    };

    LinkButton.prototype.status = function ($node) {
      var showPopover;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      if ($node == null) {
        return this.active;
      }
      showPopover = true;
      if (!$node.is(this.htmlTag) || $node.is('[class^="simditor-"]')) {
        this.setActive(false);
        showPopover = false;
      } else if (this.editor.selection.rangeAtEndOf($node)) {
        this.setActive(true);
        showPopover = false;
      } else {
        this.setActive(true);
      }
      if (showPopover) {
        this.popover.show($node);
      } else if (this.editor.util.isBlockNode($node)) {
        this.popover.hide();
      }
      return this.active;
    };

    LinkButton.prototype.command = function () {
      var $contents, $endBlock, $link, $newBlock, $startBlock, endNode,
          linkText, range, startNode, txtNode;
      range = this.editor.selection.getRange();
      if (this.active) {
        $link = $(range.commonAncestorContainer).closest('a');
        txtNode = document.createTextNode($link.text());
        $link.replaceWith(txtNode);
        range.selectNode(txtNode);
      } else {
        startNode = range.startContainer;
        endNode = range.endContainer;
        $startBlock = this.editor.util.closestBlockEl(startNode);
        $endBlock = this.editor.util.closestBlockEl(endNode);
        $contents = $(range.extractContents());
        linkText = this.editor.formatter.clearHtml($contents.contents(), false);
        $link = $('<a/>', {
          href: 'http://www.example.com',
          target: '_blank',
          text: linkText || this._t('linkText')
        });
        if ($startBlock[0] === $endBlock[0]) {
          range.insertNode($link[0]);
        } else {
          $newBlock = $('<p/>').append($link);
          range.insertNode($newBlock[0]);
        }
        range.selectNodeContents($link[0]);
        this.popover.one('popovershow', (function (_this) {
          return function () {
            if (linkText) {
              _this.popover.urlEl.focus();
              return _this.popover.urlEl[0].select();
            } else {
              _this.popover.textEl.focus();
              return _this.popover.textEl[0].select();
            }
          };
        })(this));
      }
      this.editor.selection.selectRange(range);
      return this.editor.trigger('valuechanged');
    };

    return LinkButton;

  })(Button);

  LinkPopover = (function (_super) {
    __extends(LinkPopover, _super);

    function LinkPopover() {
      return LinkPopover.__super__.constructor.apply(this, arguments);
    }

    LinkPopover.prototype.render = function () {
      var tpl;
      tpl = "<div class=\"link-settings\">\n  <div class=\"settings-field\">\n    <label>"
          + (this._t('text'))
          + "</label>\n    <input class=\"link-text\" type=\"text\"/>\n    <a class=\"btn-unlink\" href=\"javascript:;\" title=\""
          + (this._t('removeLink'))
          + "\" tabindex=\"-1\"><span class=\"fa fa-unlink\"></span></a>\n  </div>\n  <div class=\"settings-field\">\n    <label>"
          + (this._t('linkUrl'))
          + "</label>\n    <input class=\"link-url\" type=\"text\"/>\n  </div>\n</div>";
      this.el.addClass('link-popover').append(tpl);
      this.textEl = this.el.find('.link-text');
      this.urlEl = this.el.find('.link-url');
      this.unlinkEl = this.el.find('.btn-unlink');
      this.textEl.on('keyup', (function (_this) {
        return function (e) {
          if (e.which === 13) {
            return;
          }
          return _this.target.text(_this.textEl.val());
        };
      })(this));
      this.urlEl.on('keyup', (function (_this) {
        return function (e) {
          var val;
          if (e.which === 13) {
            return;
          }
          val = _this.urlEl.val();
          if (!(/https?:\/\/|^\//ig.test(val) || !val)) {
            val = 'http://' + val;
          }
          return _this.target.attr('href', val);
        };
      })(this));
      $([this.urlEl[0], this.textEl[0]]).on('keydown', (function (_this) {
        return function (e) {
          if (e.which === 13 || e.which === 27 || (!e.shiftKey && e.which === 9
              && $(e.target).hasClass('link-url'))) {
            e.preventDefault();
            return setTimeout(function () {
              var range;
              range = document.createRange();
              _this.editor.selection.setRangeAfter(_this.target, range);
              _this.hide();
              return _this.editor.trigger('valuechanged');
            }, 0);
          }
        };
      })(this));
      return this.unlinkEl.on('click', (function (_this) {
        return function (e) {
          var range, txtNode;
          txtNode = document.createTextNode(_this.target.text());
          _this.target.replaceWith(txtNode);
          _this.hide();
          range = document.createRange();
          _this.editor.selection.setRangeAfter(txtNode, range);
          return _this.editor.trigger('valuechanged');
        };
      })(this));
    };

    LinkPopover.prototype.show = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      LinkPopover.__super__.show.apply(this, args);
      this.textEl.val(this.target.text());
      return this.urlEl.val(this.target.attr('href'));
    };

    return LinkPopover;

  })(Popover);

  Simditor.Toolbar.addButton(LinkButton);

  var ImageButton, ImagePopover,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      },
      __slice = [].slice;

  ImageButton = (function (_super) {
    __extends(ImageButton, _super);

    function ImageButton() {
      return ImageButton.__super__.constructor.apply(this, arguments);
    }

    ImageButton.prototype.name = 'image';

    ImageButton.prototype.icon = 'picture-o';

    ImageButton.prototype.htmlTag = 'img';

    ImageButton.prototype.disableTag = 'pre, table';

    ImageButton.prototype.defaultImage = '';

    ImageButton.prototype.needFocus = false;

    ImageButton.prototype._init = function () {
      if (this.editor.uploader != null) {
        this.menu = [
          {
            name: 'upload-image',
            text: this._t('localImage')
          }, {
            name: 'external-image',
            text: this._t('externalImage')
          }
        ];
      } else {
        this.menu = false;
      }
      this.defaultImage = this.editor.opts.defaultImage;
      this.editor.body.on('click', 'img:not([data-non-image])',
          (function (_this) {
            return function (e) {
              var $img, range;
              $img = $(e.currentTarget);
              range = document.createRange();
              range.selectNode($img[0]);
              _this.editor.selection.selectRange(range);
              if (!_this.editor.util.supportSelectionChange) {
                _this.editor.trigger('selectionchanged');
              }
              return false;
            };
          })(this));
      this.editor.body.on('mouseup', 'img:not([data-non-image])',
          (function (_this) {
            return function (e) {
              return false;
            };
          })(this));
      this.editor.on('selectionchanged.image', (function (_this) {
        return function () {
          var $contents, $img, range;
          range = _this.editor.selection.getRange();
          if (range == null) {
            return;
          }
          $contents = $(range.cloneContents()).contents();
          if ($contents.length === 1 && $contents.is(
              'img:not([data-non-image])')) {
            $img = $(range.startContainer).contents().eq(range.startOffset);
            return _this.popover.show($img);
          } else {
            return _this.popover.hide();
          }
        };
      })(this));
      this.editor.on('valuechanged.image', (function (_this) {
        return function () {
          var $masks;
          $masks = _this.editor.wrapper.find('.simditor-image-loading');
          if (!($masks.length > 0)) {
            return;
          }
          return $masks.each(function (i, mask) {
            var $img, $mask, file;
            $mask = $(mask);
            $img = $mask.data('img');
            if (!($img && $img.parent().length > 0)) {
              $mask.remove();
              if ($img) {
                file = $img.data('file');
                if (file) {
                  _this.editor.uploader.cancel(file);
                  if (_this.editor.body.find('img.uploading').length < 1) {
                    return _this.editor.uploader.trigger('uploadready', [file]);
                  }
                }
              }
            }
          });
        };
      })(this));
      return ImageButton.__super__._init.call(this);
    };

    ImageButton.prototype.render = function () {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      ImageButton.__super__.render.apply(this, args);
      return this.popover = new ImagePopover({
        button: this
      });
    };

    ImageButton.prototype.renderMenu = function () {
      var $input, $uploadItem, createInput;
      ImageButton.__super__.renderMenu.call(this);
      $uploadItem = this.menuEl.find('.menu-item-upload-image');
      $input = null;
      createInput = (function (_this) {
        return function () {
          if ($input) {
            $input.remove();
          }
          return $input = $(
              '<input type="file" title="' + _this._t('uploadImage')
              + '" accept="image/*">').appendTo($uploadItem);
        };
      })(this);
      createInput();
      $uploadItem.on('click mousedown', 'input[type=file]', (function (_this) {
        return function (e) {
          return e.stopPropagation();
        };
      })(this));
      $uploadItem.on('change', 'input[type=file]', (function (_this) {
        return function (e) {
          if (_this.editor.inputManager.focused) {
            _this.editor.uploader.upload($input, {
              inline: true
            });
            createInput();
          } else {
            _this.editor.one('focus', function (e) {
              _this.editor.uploader.upload($input, {
                inline: true
              });
              return createInput();
            });
            _this.editor.focus();
          }
          return _this.wrapper.removeClass('menu-on');
        };
      })(this));
      return this._initUploader();
    };

    ImageButton.prototype._initUploader = function () {
      if (this.editor.uploader == null) {
        this.el.find('.btn-upload').remove();
        return;
      }
      this.editor.uploader.on('beforeupload', (function (_this) {
        return function (e, file) {
          var $img;
          if (!file.inline) {
            return;
          }
          if (file.img) {
            $img = $(file.img);
          } else {
            $img = _this.createImage(file.name);
            file.img = $img;
          }
          $img.addClass('uploading');
          $img.data('file', file);
          return _this.editor.uploader.readImageFile(file.obj, function (img) {
            var src;
            if (!$img.hasClass('uploading')) {
              return;
            }
            src = img ? img.src : _this.defaultImage;
            return _this.loadImage($img, src, function () {
              if (_this.popover.active) {
                _this.popover.refresh();
                return _this.popover.srcEl.val(_this._t('uploading')).prop(
                    'disabled', true);
              }
            });
          });
        };
      })(this));
      this.editor.uploader.on('uploadprogress', (function (_this) {
        return function (e, file, loaded, total) {
          var $img, $mask, $txt, percent;
          if (!file.inline) {
            return;
          }
          percent = loaded / total;
          percent = (percent * 100).toFixed(0);
          if (percent > 99) {
            percent = 99;
          }
          $mask = file.img.data('mask');
          if ($mask) {
            $img = $mask.data('img');
            $txt = $mask.find('span');
            if ($img && $img.parent().length > 0 && percent !== $txt.text()) {
              return $txt.text(percent);
            } else {
              return $mask.remove();
            }
          }
        };
      })(this));
      this.editor.uploader.on('uploadsuccess', (function (_this) {
        return function (e, file, result) {
          var $img, $mask, msg;
          if (!file.inline) {
            return;
          }
          $img = file.img;
          $img.removeData('file');
          $img.removeClass('uploading');
          $mask = $img.data('mask');
          if ($mask) {
            $mask.remove();
          }
          $img.removeData('mask');
          if (result.success === false) {
            msg = result.msg || _this._t('uploadFailed');
            alert(msg);
            $img.attr('src', _this.defaultImage);
          } else {
            $img.attr('src', result.file_path);
          }
          if (_this.popover.active) {
            _this.popover.srcEl.prop('disabled', false);
            _this.popover.srcEl.val(result.file_path);
          }
          _this.editor.trigger('valuechanged');
          if (_this.editor.body.find('img.uploading').length < 1) {
            return _this.editor.uploader.trigger('uploadready', [file, result]);
          }
        };
      })(this));
      return this.editor.uploader.on('uploaderror', (function (_this) {
        return function (e, file, xhr) {
          var $img, $mask, msg, result;
          if (!file.inline) {
            return;
          }
          if (xhr.statusText === 'abort') {
            return;
          }
          if (xhr.responseText) {
            try {
              result = $.parseJSON(xhr.responseText);
              msg = result.msg;
            } catch (_error) {
              e = _error;
              msg = _this._t('uploadError');
            }
            alert(msg);
          }
          $img = file.img;
          $img.removeData('file');
          $img.removeClass('uploading');
          $mask = $img.data('mask');
          if ($mask) {
            $mask.remove();
          }
          $img.removeData('mask');
          $img.attr('src', _this.defaultImage);
          if (_this.popover.active) {
            _this.popover.srcEl.prop('disabled', false);
            _this.popover.srcEl.val(_this.defaultImage);
          }
          _this.editor.trigger('valuechanged');
          if (_this.editor.body.find('img.uploading').length < 1) {
            return _this.editor.uploader.trigger('uploadready', [file, result]);
          }
        };
      })(this));
    };

    ImageButton.prototype.status = function ($node) {
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
    };

    ImageButton.prototype.loadImage = function ($img, src, callback) {
      var $mask, img;
      $mask = $img.data('mask');
      if (!$mask) {
        $mask = $(
            '<div class="simditor-image-loading"><span></span></div>').hide().appendTo(
            this.editor.wrapper);
        if ($img.hasClass('uploading')) {
          $mask.addClass('uploading');
        }
        $img.data('mask', $mask);
        $mask.data('img', $img);
      }
      img = new Image();
      img.onload = (function (_this) {
        return function () {
          var height, imgOffset, width, wrapperOffset;
          if ($mask.hasClass('uploading') && !$img.hasClass('uploading')) {
            return;
          }
          width = img.width;
          height = img.height;
          $img.attr({
            src: src,
            'data-image-size': width + ',' + height
          });
          if ($img.hasClass('uploading')) {
            _this.editor.util.reflow(_this.editor.body);
            wrapperOffset = _this.editor.wrapper.offset();
            imgOffset = $img.offset();
            $mask.css({
              top: imgOffset.top - wrapperOffset.top,
              left: imgOffset.left - wrapperOffset.left,
              width: $img.width(),
              height: $img.height()
            }).show();
          } else {
            $mask.remove();
            $img.removeData('mask');
          }
          return callback(img);
        };
      })(this);
      img.onerror = (function (_this) {
        return function () {
          callback(false);
          $mask.remove();
          return $img.removeData('mask');
        };
      })(this);
      return img.src = src;
    };

    ImageButton.prototype.createImage = function (name) {
      var $block, $img, $nextBlock, range;
      if (name == null) {
        name = 'Image';
      }
      if (!this.editor.inputManager.focused) {
        this.editor.focus();
      }
      range = this.editor.selection.getRange();
      range.deleteContents();
      $block = this.editor.util.closestBlockEl();
      if ($block.is('p') && !this.editor.util.isEmptyNode($block)) {
        $block = $('<p/>').append(this.editor.util.phBr).insertAfter($block);
        this.editor.selection.setRangeAtStartOf($block, range);
      }
      $img = $('<img/>').attr('alt', name);
      range.insertNode($img[0]);
      $nextBlock = $block.next('p');
      if (!($nextBlock.length > 0)) {
        $nextBlock = $('<p/>').append(this.editor.util.phBr).insertAfter(
            $block);
      }
      this.editor.selection.setRangeAtStartOf($nextBlock);
      return $img;
    };

    ImageButton.prototype.command = function (src) {
      var $img;
      $img = this.createImage();
      return this.loadImage($img, src || this.defaultImage, (function (_this) {
        return function () {
          _this.editor.trigger('valuechanged');
          _this.editor.util.reflow($img);
          $img.click();
          return _this.popover.one('popovershow', function () {
            _this.popover.srcEl.focus();
            return _this.popover.srcEl[0].select();
          });
        };
      })(this));
    };

    return ImageButton;

  })(Button);

  ImagePopover = (function (_super) {
    __extends(ImagePopover, _super);

    function ImagePopover() {
      return ImagePopover.__super__.constructor.apply(this, arguments);
    }

    ImagePopover.prototype.offset = {
      top: 6,
      left: -4
    };

    ImagePopover.prototype.render = function () {
      var tpl;
      tpl = "<div class=\"link-settings\">\n  <div class=\"settings-field\">\n    <label>"
          + (this._t('imageUrl'))
          + "</label>\n    <input class=\"image-src\" type=\"text\" tabindex=\"1\" />\n    <a class=\"btn-upload\" href=\"javascript:;\" title=\""
          + (this._t('uploadImage'))
          + "\" tabindex=\"-1\">\n      <span class=\"fa fa-upload\"></span>\n    </a>\n  </div>\n  <div class=\"settings-field\">\n    <label>"
          + (this._t('imageSize'))
          + "</label>\n    <input class=\"image-size\" id=\"image-width\" type=\"text\" tabindex=\"2\" />\n    <span class=\"times\">×</span>\n    <input class=\"image-size\" id=\"image-height\" type=\"text\" tabindex=\"3\" />\n    <a class=\"btn-restore\" href=\"javascript:;\" title=\""
          + (this._t('restoreImageSize'))
          + "\" tabindex=\"-1\">\n      <span class=\"fa fa-reply\"></span>\n    </a>\n  </div>\n</div>";
      this.el.addClass('image-popover').append(tpl);
      this.srcEl = this.el.find('.image-src');
      this.srcEl.on('keydown', (function (_this) {
        return function (e) {
          var hideAndFocus, src;
          if (!(e.which === 13 || e.which === 27)) {
            return;
          }
          e.preventDefault();
          hideAndFocus = function () {
            _this.button.editor.body.focus();
            _this.button.editor.selection.setRangeAfter(_this.target);
            return _this.hide();
          };
          if (e.which === 13 && !_this.target.hasClass('uploading')) {
            src = _this.srcEl.val();
            if (/^data:image/.test(src) && !_this.editor.uploader) {
              hideAndFocus();
              return;
            }
            return _this.button.loadImage(_this.target, src,
                function (success) {
                  var blob;
                  if (!success) {
                    return;
                  }
                  if (/^data:image/.test(src)) {
                    blob = _this.editor.util.dataURLtoBlob(src);
                    blob.name = "Base64 Image.png";
                    return _this.editor.uploader.upload(blob, {
                      inline: true,
                      img: _this.target
                    });
                  } else {
                    hideAndFocus();
                    return _this.editor.trigger('valuechanged');
                  }
                });
          } else {
            return hideAndFocus();
          }
        };
      })(this));
      this.widthEl = this.el.find('#image-width');
      this.heightEl = this.el.find('#image-height');
      this.el.find('.image-size').on('blur', (function (_this) {
        return function (e) {
          _this._resizeImg($(e.currentTarget));
          return _this.el.data('popover').refresh();
        };
      })(this));
      this.el.find('.image-size').on('keyup', (function (_this) {
        return function (e) {
          var inputEl;
          inputEl = $(e.currentTarget);
          if (!(e.which === 13 || e.which === 27 || e.which === 9)) {
            return _this._resizeImg(inputEl, true);
          }
        };
      })(this));
      this.el.find('.image-size').on('keydown', (function (_this) {
        return function (e) {
          var inputEl;
          inputEl = $(e.currentTarget);
          if (e.which === 13 || e.which === 27) {
            e.preventDefault();
            if (e.which === 13) {
              _this._resizeImg(inputEl);
            } else {
              _this._restoreImg();
            }
            _this.button.editor.body.focus();
            _this.button.editor.selection.setRangeAfter(_this.target);
            return _this.hide();
          } else if (e.which === 9) {
            return _this.el.data('popover').refresh();
          }
        };
      })(this));
      this.el.find('.btn-restore').on('click', (function (_this) {
        return function (e) {
          _this._restoreImg();
          return _this.el.data('popover').refresh();
        };
      })(this));
      this.editor.on('valuechanged', (function (_this) {
        return function (e) {
          if (_this.active) {
            return _this.refresh();
          }
        };
      })(this));
      return this._initUploader();
    };

    ImagePopover.prototype._initUploader = function () {
      var $uploadBtn, createInput;
      $uploadBtn = this.el.find('.btn-upload');
      if (this.editor.uploader == null) {
        $uploadBtn.remove();
        return;
      }
      createInput = (function (_this) {
        return function () {
          if (_this.input) {
            _this.input.remove();
          }
          return _this.input = $(
              '<input type="file" title="' + _this._t('uploadImage')
              + '" accept="image/*">').appendTo($uploadBtn);
        };
      })(this);
      createInput();
      this.el.on('click mousedown', 'input[type=file]', (function (_this) {
        return function (e) {
          return e.stopPropagation();
        };
      })(this));
      return this.el.on('change', 'input[type=file]', (function (_this) {
        return function (e) {
          _this.editor.uploader.upload(_this.input, {
            inline: true,
            img: _this.target
          });
          return createInput();
        };
      })(this));
    };

    ImagePopover.prototype._resizeImg = function (inputEl, onlySetVal) {
      var height, value, width;
      if (onlySetVal == null) {
        onlySetVal = false;
      }
      value = inputEl.val() * 1;
      if (!($.isNumeric(value) || value < 0)) {
        return;
      }
      if (inputEl.is(this.widthEl)) {
        height = this.height * value / this.width;
        this.heightEl.val(height);
      } else {
        width = this.width * value / this.height;
        this.widthEl.val(width);
      }
      if (!onlySetVal) {
        return this.target.attr({
          width: width || value,
          height: height || value
        });
      }
    };

    ImagePopover.prototype._restoreImg = function () {
      var size, _ref;
      size = ((_ref = this.target.data('image-size')) != null ? _ref.split(",")
          : void 0) || [this.width, this.height];
      this.target.attr({
        width: size[0] * 1,
        height: size[1] * 1
      });
      this.widthEl.val(size[0]);
      return this.heightEl.val(size[1]);
    };

    ImagePopover.prototype.show = function () {
      var $img, args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      ImagePopover.__super__.show.apply(this, args);
      $img = this.target;
      this.width = $img.width();
      this.height = $img.height();
      if ($img.hasClass('uploading')) {
        return this.srcEl.val(this._t('uploading')).prop('disabled', true);
      } else {
        this.srcEl.val($img.attr('src')).prop('disabled', false);
        this.widthEl.val(this.width);
        return this.heightEl.val(this.height);
      }
    };

    return ImagePopover;

  })(Popover);

  Simditor.Toolbar.addButton(ImageButton);

  var IndentButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  IndentButton = (function (_super) {
    __extends(IndentButton, _super);

    function IndentButton() {
      return IndentButton.__super__.constructor.apply(this, arguments);
    }

    IndentButton.prototype.name = 'indent';

    IndentButton.prototype.icon = 'indent';

    IndentButton.prototype._init = function () {
      this.title = this._t(this.name) + ' (Tab)';
      return IndentButton.__super__._init.call(this);
    };

    IndentButton.prototype.status = function ($node) {
      return true;
    };

    IndentButton.prototype.command = function () {
      return this.editor.util.indent();
    };

    return IndentButton;

  })(Button);

  Simditor.Toolbar.addButton(IndentButton);

  var OutdentButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  OutdentButton = (function (_super) {
    __extends(OutdentButton, _super);

    function OutdentButton() {
      return OutdentButton.__super__.constructor.apply(this, arguments);
    }

    OutdentButton.prototype.name = 'outdent';

    OutdentButton.prototype.icon = 'outdent';

    OutdentButton.prototype._init = function () {
      this.title = this._t(this.name) + ' (Shift + Tab)';
      return OutdentButton.__super__._init.call(this);
    };

    OutdentButton.prototype.status = function ($node) {
      return true;
    };

    OutdentButton.prototype.command = function () {
      return this.editor.util.outdent();
    };

    return OutdentButton;

  })(Button);

  Simditor.Toolbar.addButton(OutdentButton);

  var HrButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  HrButton = (function (_super) {
    __extends(HrButton, _super);

    function HrButton() {
      return HrButton.__super__.constructor.apply(this, arguments);
    }

    HrButton.prototype.name = 'hr';

    HrButton.prototype.icon = 'minus';

    HrButton.prototype.htmlTag = 'hr';

    HrButton.prototype.status = function ($node) {
      return true;
    };

    HrButton.prototype.command = function () {
      var $hr, $newBlock, $nextBlock, $rootBlock;
      $rootBlock = this.editor.util.furthestBlockEl();
      $nextBlock = $rootBlock.next();
      if ($nextBlock.length > 0) {
        this.editor.selection.save();
      } else {
        $newBlock = $('<p/>').append(this.editor.util.phBr);
      }
      $hr = $('<hr/>').insertAfter($rootBlock);
      if ($newBlock) {
        $newBlock.insertAfter($hr);
        this.editor.selection.setRangeAtStartOf($newBlock);
      } else {
        this.editor.selection.restore();
      }
      return this.editor.trigger('valuechanged');
    };

    return HrButton;

  })(Button);

  Simditor.Toolbar.addButton(HrButton);

  var TableButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  TableButton = (function (_super) {
    __extends(TableButton, _super);

    function TableButton() {
      return TableButton.__super__.constructor.apply(this, arguments);
    }

    TableButton.prototype.name = 'table';

    TableButton.prototype.icon = 'table';

    TableButton.prototype.htmlTag = 'table';

    TableButton.prototype.disableTag = 'pre, li, blockquote';

    TableButton.prototype.menu = true;

    TableButton.prototype._init = function () {
      TableButton.__super__._init.call(this);
      $.merge(this.editor.formatter._allowedTags,
          ['tbody', 'tr', 'td', 'colgroup', 'col']);
      $.extend(this.editor.formatter._allowedAttributes, {
        td: ['rowspan', 'colspan'],
        col: ['width']
      });
      this._initShortcuts();
      this.editor.on('decorate', (function (_this) {
        return function (e, $el) {
          return $el.find('table').each(function (i, table) {
            return _this.decorate($(table));
          });
        };
      })(this));
      this.editor.on('undecorate', (function (_this) {
        return function (e, $el) {
          return $el.find('table').each(function (i, table) {
            return _this.undecorate($(table));
          });
        };
      })(this));
      this.editor.on('selectionchanged.table', (function (_this) {
        return function (e) {
          var $container, range;
          _this.editor.body.find('.simditor-table td').removeClass('active');
          range = _this.editor.selection.getRange();
          if (range == null) {
            return;
          }
          $container = $(range.commonAncestorContainer);
          if (range.collapsed && $container.is('.simditor-table')) {
            if (_this.editor.selection.rangeAtStartOf($container)) {
              $container = $container.find('td:first');
            } else {
              $container = $container.find('td:last');
            }
            _this.editor.selection.setRangeAtEndOf($container);
          }
          return $container.closest('td', _this.editor.body).addClass('active');
        };
      })(this));
      this.editor.on('blur.table', (function (_this) {
        return function (e) {
          return _this.editor.body.find('.simditor-table td').removeClass(
              'active');
        };
      })(this));
      this.editor.inputManager.addKeystrokeHandler('38', 'td',
          (function (_this) {
            return function (e, $node) {
              var $prevTr, $tr, index;
              $tr = $node.parent('tr');
              $prevTr = $tr.prev('tr');
              if (!($prevTr.length > 0)) {
                return true;
              }
              index = $tr.find('td').index($node);
              _this.editor.selection.setRangeAtEndOf(
                  $prevTr.find('td').eq(index));
              return true;
            };
          })(this));
      return this.editor.inputManager.addKeystrokeHandler('40', 'td',
          (function (_this) {
            return function (e, $node) {
              var $nextTr, $tr, index;
              $tr = $node.parent('tr');
              $nextTr = $tr.next('tr');
              if (!($nextTr.length > 0)) {
                return true;
              }
              index = $tr.find('td').index($node);
              _this.editor.selection.setRangeAtEndOf(
                  $nextTr.find('td').eq(index));
              return true;
            };
          })(this));
    };

    TableButton.prototype.initResize = function ($table) {
      var $colgroup, $resizeHandle, $wrapper;
      $wrapper = $table.parent('.simditor-table');
      $colgroup = $table.find('colgroup');
      if ($colgroup.length < 1) {
        $colgroup = $('<colgroup/>').prependTo($table);
        $table.find('tr:first td').each((function (_this) {
          return function (i, td) {
            var $col;
            return $col = $('<col/>').appendTo($colgroup);
          };
        })(this));
        this.refreshTableWidth($table);
      }
      $resizeHandle = $(
          '<div class="simditor-resize-handle" contenteditable="false"></div>').appendTo(
          $wrapper);
      $wrapper.on('mousemove', 'td', (function (_this) {
        return function (e) {
          var $col, $td, index, x, _ref, _ref1;
          if ($wrapper.hasClass('resizing')) {
            return;
          }
          $td = $(e.currentTarget);
          x = e.pageX - $(e.currentTarget).offset().left;
          if (x < 5 && $td.prev().length > 0) {
            $td = $td.prev();
          }
          if ($td.next('td').length < 1) {
            $resizeHandle.hide();
            return;
          }
          if ((_ref = $resizeHandle.data('td')) != null ? _ref.is($td)
              : void 0) {
            $resizeHandle.show();
            return;
          }
          index = $td.parent().find('td').index($td);
          $col = $colgroup.find('col').eq(index);
          if ((_ref1 = $resizeHandle.data('col')) != null ? _ref1.is($col)
              : void 0) {
            $resizeHandle.show();
            return;
          }
          return $resizeHandle.css('left',
              $td.position().left + $td.outerWidth() - 5).data('td', $td).data(
              'col', $col).show();
        };
      })(this));
      $wrapper.on('mouseleave', (function (_this) {
        return function (e) {
          return $resizeHandle.hide();
        };
      })(this));
      return $wrapper.on('mousedown', '.simditor-resize-handle',
          (function (_this) {
            return function (e) {
              var $handle, $leftCol, $leftTd, $rightCol, $rightTd, minWidth,
                  startHandleLeft, startLeftWidth, startRightWidth, startX,
                  tableWidth;
              $handle = $(e.currentTarget);
              $leftTd = $handle.data('td');
              $leftCol = $handle.data('col');
              $rightTd = $leftTd.next('td');
              $rightCol = $leftCol.next('col');
              startX = e.pageX;
              startLeftWidth = $leftTd.outerWidth() * 1;
              startRightWidth = $rightTd.outerWidth() * 1;
              startHandleLeft = parseFloat($handle.css('left'));
              tableWidth = $leftTd.closest('table').width();
              minWidth = 50;
              $(document).on('mousemove.simditor-resize-table', function (e) {
                var deltaX, leftWidth, rightWidth;
                deltaX = e.pageX - startX;
                leftWidth = startLeftWidth + deltaX;
                rightWidth = startRightWidth - deltaX;
                if (leftWidth < minWidth) {
                  leftWidth = minWidth;
                  deltaX = minWidth - startLeftWidth;
                  rightWidth = startRightWidth - deltaX;
                } else if (rightWidth < minWidth) {
                  rightWidth = minWidth;
                  deltaX = startRightWidth - minWidth;
                  leftWidth = startLeftWidth + deltaX;
                }
                $leftCol.attr('width', (leftWidth / tableWidth * 100) + '%');
                $rightCol.attr('width', (rightWidth / tableWidth * 100) + '%');
                return $handle.css('left', startHandleLeft + deltaX);
              });
              $(document).one('mouseup.simditor-resize-table', function (e) {
                $(document).off('.simditor-resize-table');
                return $wrapper.removeClass('resizing');
              });
              $wrapper.addClass('resizing');
              return false;
            };
          })(this));
    };

    TableButton.prototype._initShortcuts = function () {
      this.editor.inputManager.addShortcut('ctrl+alt+up', (function (_this) {
        return function (e) {
          _this.editMenu.find('.menu-item[data-param=insertRowAbove]').click();
          return false;
        };
      })(this));
      this.editor.inputManager.addShortcut('ctrl+alt+down', (function (_this) {
        return function (e) {
          _this.editMenu.find('.menu-item[data-param=insertRowBelow]').click();
          return false;
        };
      })(this));
      this.editor.inputManager.addShortcut('ctrl+alt+left', (function (_this) {
        return function (e) {
          _this.editMenu.find('.menu-item[data-param=insertColLeft]').click();
          return false;
        };
      })(this));
      return this.editor.inputManager.addShortcut('ctrl+alt+right',
          (function (_this) {
            return function (e) {
              _this.editMenu.find(
                  '.menu-item[data-param=insertColRight]').click();
              return false;
            };
          })(this));
    };

    TableButton.prototype.decorate = function ($table) {
      if ($table.parent('.simditor-table').length > 0) {
        this.undecorate($table);
      }
      $table.wrap('<div class="simditor-table"></div>');
      this.initResize($table);
      return $table.parent();
    };

    TableButton.prototype.undecorate = function ($table) {
      if (!($table.parent('.simditor-table').length > 0)) {
        return;
      }
      return $table.parent().replaceWith($table);
    };

    TableButton.prototype.renderMenu = function () {
      $("<div class=\"menu-create-table\">\n</div>\n<div class=\"menu-edit-table\">\n  <ul>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteRow\"><span>"
          + (this._t('deleteRow'))
          + " ( Ctrl + Alt + → )</span></a></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertRowAbove\"><span>"
          + (this._t('insertRowAbove'))
          + " ( Ctrl + Alt + ↑ )</span></a></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertRowBelow\"><span>"
          + (this._t('insertRowBelow'))
          + " ( Ctrl + Alt + ↓ )</span></a></li>\n    <li><span class=\"separator\"></span></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteCol\"><span>"
          + (this._t('deleteColumn'))
          + "</span></a></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertColLeft\"><span>"
          + (this._t('insertColumnLeft'))
          + " ( Ctrl + Alt + ← )</span></a></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"insertColRight\"><span>"
          + (this._t('insertColumnRight'))
          + " ( Ctrl + Alt + → )</span></a></li>\n    <li><span class=\"separator\"></span></li>\n    <li><a tabindex=\"-1\" unselectable=\"on\" class=\"menu-item\" href=\"javascript:;\" data-param=\"deleteTable\"><span>"
          + (this._t('deleteTable'))
          + "</span></a></li>\n  </ul>\n</div>").appendTo(this.menuWrapper);
      this.createMenu = this.menuWrapper.find('.menu-create-table');
      this.editMenu = this.menuWrapper.find('.menu-edit-table');
      this.createTable(6, 6).appendTo(this.createMenu);
      this.createMenu.on('mouseenter', 'td', (function (_this) {
        return function (e) {
          var $td, $tr, num;
          _this.createMenu.find('td').removeClass('selected');
          $td = $(e.currentTarget);
          $tr = $td.parent();
          num = $tr.find('td').index($td) + 1;
          return $tr.prevAll('tr').addBack().find(
              'td:lt(' + num + ')').addClass('selected');
        };
      })(this));
      this.createMenu.on('mouseleave', (function (_this) {
        return function (e) {
          return $(e.currentTarget).find('td').removeClass('selected');
        };
      })(this));
      return this.createMenu.on('mousedown', 'td', (function (_this) {
        return function (e) {
          var $closestBlock, $table, $td, $tr, colNum, rowNum;
          _this.wrapper.removeClass('menu-on');
          if (!_this.editor.inputManager.focused) {
            return;
          }
          $td = $(e.currentTarget);
          $tr = $td.parent();
          colNum = $tr.find('td').index($td) + 1;
          rowNum = $tr.prevAll('tr').length + 1;
          $table = _this.createTable(rowNum, colNum, true);
          $closestBlock = _this.editor.util.closestBlockEl();
          if (_this.editor.util.isEmptyNode($closestBlock)) {
            $closestBlock.replaceWith($table);
          } else {
            $closestBlock.after($table);
          }
          _this.decorate($table);
          _this.editor.selection.setRangeAtStartOf($table.find('td:first'));
          _this.editor.trigger('valuechanged');
          return false;
        };
      })(this));
    };

    TableButton.prototype.createTable = function (row, col, phBr) {
      var $table, $tbody, $td, $tr, c, r, _i, _j;
      $table = $('<table/>');
      $tbody = $('<tbody/>').appendTo($table);
      for (r = _i = 0; 0 <= row ? _i < row : _i > row;
          r = 0 <= row ? ++_i : --_i) {
        $tr = $('<tr/>').appendTo($tbody);
        for (c = _j = 0; 0 <= col ? _j < col : _j > col;
            c = 0 <= col ? ++_j : --_j) {
          $td = $('<td/>').appendTo($tr);
          if (phBr) {
            $td.append(this.editor.util.phBr);
          }
        }
      }
      return $table;
    };

    TableButton.prototype.refreshTableWidth = function ($table) {
      var cols, tableWidth;
      tableWidth = $table.width();
      cols = $table.find('col');
      return $table.find('tr:first td').each((function (_this) {
        return function (i, td) {
          var $col;
          $col = cols.eq(i);
          return $col.attr('width',
              ($(td).outerWidth() / tableWidth * 100) + '%');
        };
      })(this));
    };

    TableButton.prototype.setActive = function (active) {
      TableButton.__super__.setActive.call(this, active);
      if (active) {
        this.createMenu.hide();
        return this.editMenu.show();
      } else {
        this.createMenu.show();
        return this.editMenu.hide();
      }
    };

    TableButton.prototype.deleteRow = function ($td) {
      var $newTr, $tr, index;
      $tr = $td.parent('tr');
      if ($tr.siblings('tr').length < 1) {
        return this.deleteTable($td);
      } else {
        $newTr = $tr.next('tr');
        if (!($newTr.length > 0)) {
          $newTr = $tr.prev('tr');
        }
        index = $tr.find('td').index($td);
        $tr.remove();
        return this.editor.selection.setRangeAtEndOf(
            $newTr.find('td').eq(index));
      }
    };

    TableButton.prototype.insertRow = function ($td, direction) {
      var $newTr, $table, $tr, colNum, i, index, _i;
      if (direction == null) {
        direction = 'after';
      }
      $tr = $td.parent('tr');
      $table = $tr.closest('table');
      colNum = 0;
      $table.find('tr').each((function (_this) {
        return function (i, tr) {
          return colNum = Math.max(colNum, $(tr).find('td').length);
        };
      })(this));
      $newTr = $('<tr/>');
      for (i = _i = 1; 1 <= colNum ? _i <= colNum : _i >= colNum;
          i = 1 <= colNum ? ++_i : --_i) {
        $('<td/>').append(this.editor.util.phBr).appendTo($newTr);
      }
      $tr[direction]($newTr);
      index = $tr.find('td').index($td);
      return this.editor.selection.setRangeAtStartOf(
          $newTr.find('td').eq(index));
    };

    TableButton.prototype.deleteCol = function ($td) {
      var $newTd, $table, $tr, index;
      $tr = $td.parent('tr');
      if ($tr.siblings('tr').length < 1 && $td.siblings('td').length < 1) {
        return this.deleteTable($td);
      } else {
        index = $tr.find('td').index($td);
        $newTd = $td.next('td');
        if (!($newTd.length > 0)) {
          $newTd = $tr.prev('td');
        }
        $table = $tr.closest('table');
        $table.find('col').eq(index).remove();
        $table.find('tr').each((function (_this) {
          return function (i, tr) {
            return $(tr).find('td').eq(index).remove();
          };
        })(this));
        this.refreshTableWidth($table);
        return this.editor.selection.setRangeAtEndOf($newTd);
      }
    };

    TableButton.prototype.insertCol = function ($td, direction) {
      var $col, $newCol, $newTd, $table, $tr, index, tableWidth, width;
      if (direction == null) {
        direction = 'after';
      }
      $tr = $td.parent('tr');
      index = $tr.find('td').index($td);
      $table = $td.closest('table');
      $col = $table.find('col').eq(index);
      $table.find('tr').each((function (_this) {
        return function (i, tr) {
          var $newTd;
          $newTd = $('<td/>').append(_this.editor.util.phBr);
          return $(tr).find('td').eq(index)[direction]($newTd);
        };
      })(this));
      $newCol = $('<col/>');
      $col[direction]($newCol);
      tableWidth = $table.width();
      width = Math.max(parseFloat($col.attr('width')) / 2,
          50 / tableWidth * 100);
      $col.attr('width', width + '%');
      $newCol.attr('width', width + '%');
      this.refreshTableWidth($table);
      $newTd = direction === 'after' ? $td.next('td') : $td.prev('td');
      return this.editor.selection.setRangeAtStartOf($newTd);
    };

    TableButton.prototype.deleteTable = function ($td) {
      var $block, $table;
      $table = $td.closest('.simditor-table');
      $block = $table.next('p');
      $table.remove();
      if ($block.length > 0) {
        return this.editor.selection.setRangeAtStartOf($block);
      }
    };

    TableButton.prototype.command = function (param) {
      var $td, range;
      range = this.editor.selection.getRange();
      $td = $(range.commonAncestorContainer).closest('td');
      if (!($td.length > 0)) {
        return;
      }
      if (param === 'deleteRow') {
        this.deleteRow($td);
      } else if (param === 'insertRowAbove') {
        this.insertRow($td, 'before');
      } else if (param === 'insertRowBelow') {
        this.insertRow($td);
      } else if (param === 'deleteCol') {
        this.deleteCol($td);
      } else if (param === 'insertColLeft') {
        this.insertCol($td, 'before');
      } else if (param === 'insertColRight') {
        this.insertCol($td);
      } else if (param === 'deleteTable') {
        this.deleteTable($td);
      } else {
        return;
      }
      return this.editor.trigger('valuechanged');
    };

    return TableButton;

  })(Button);

  Simditor.Toolbar.addButton(TableButton);

  var StrikethroughButton,
      __hasProp = {}.hasOwnProperty,
      __extends = function (child, parent) {
        for (var key in parent) {
          if (__hasProp.call(parent, key)) {
            child[key] = parent[key];
          }
        }

        function ctor() {
          this.constructor = child;
        }

        ctor.prototype = parent.prototype;
        child.prototype = new ctor();
        child.__super__ = parent.prototype;
        return child;
      };

  StrikethroughButton = (function (_super) {
    __extends(StrikethroughButton, _super);

    function StrikethroughButton() {
      return StrikethroughButton.__super__.constructor.apply(this, arguments);
    }

    StrikethroughButton.prototype.name = 'strikethrough';

    StrikethroughButton.prototype.icon = 'strikethrough';

    StrikethroughButton.prototype.htmlTag = 'strike';

    StrikethroughButton.prototype.disableTag = 'pre';

    StrikethroughButton.prototype.status = function ($node) {
      var active;
      if ($node != null) {
        this.setDisabled($node.is(this.disableTag));
      }
      if (this.disabled) {
        return true;
      }
      active = document.queryCommandState('strikethrough') === true;
      this.setActive(active);
      return active;
    };

    StrikethroughButton.prototype.command = function () {
      document.execCommand('strikethrough');
      this.editor.trigger('valuechanged');
      return $(document).trigger('selectionchange');
    };

    return StrikethroughButton;

  })(Button);

  Simditor.Toolbar.addButton(StrikethroughButton);

  return Simditor;

}));
